diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/_snippets/functions/description/to_aggregate_metric_double.md
deleted file mode 100644
index 144c427ff07cb..0000000000000
--- a/docs/reference/query-languages/esql/_snippets/functions/description/to_aggregate_metric_double.md
+++ /dev/null
@@ -1,6 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Description**
-
-Encode a numeric to an aggregate_metric_double.
-
diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md b/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md
index f8ed6a7072437..cbab7915f6bf5 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/examples/to_lower.md
@@ -1,6 +1,6 @@
 % This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
 
-**Examples**
+**Example**
 
 ```esql
 ROW message = "Some Text"
@@ -11,12 +11,4 @@ ROW message = "Some Text"
 | --- | --- |
 | Some Text | some text |
 
-```esql
-ROW v = TO_LOWER(["Some", "Text"])
-```
-
-| v:keyword |
-| --- |
-| ["some", "text"] |
-
 
diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/_snippets/functions/layout/to_aggregate_metric_double.md
deleted file mode 100644
index ed65b3d386bcd..0000000000000
--- a/docs/reference/query-languages/esql/_snippets/functions/layout/to_aggregate_metric_double.md
+++ /dev/null
@@ -1,23 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-## `TO_AGGREGATE_METRIC_DOUBLE` [esql-to_aggregate_metric_double]
-```{applies_to}
-product: COMING 9.1
-```
-
-**Syntax**
-
-:::{image} ../../../images/functions/to_aggregate_metric_double.svg
-:alt: Embedded
-:class: text-center
-:::
-
-
-:::{include} ../parameters/to_aggregate_metric_double.md
-:::
-
-:::{include} ../description/to_aggregate_metric_double.md
-:::
-
-:::{include} ../types/to_aggregate_metric_double.md
-:::
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_aggregate_metric_double.md
deleted file mode 100644
index 5204e46661d48..0000000000000
--- a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_aggregate_metric_double.md
+++ /dev/null
@@ -1,7 +0,0 @@
-% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
-
-**Parameters**
-
-`number`
-:   Input value. The input can be a single-valued column or an expression.
-
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md
index 29bfbc291af5e..122e76c5af875 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_lower.md
@@ -3,5 +3,5 @@
 **Parameters**
 
 `str`
-:   String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression.
+:   String expression. If `null`, the function returns `null`.
 
diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md
index 29bfbc291af5e..122e76c5af875 100644
--- a/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md
+++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/to_upper.md
@@ -3,5 +3,5 @@
 **Parameters**
 
 `str`
-:   String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression.
+:   String expression. If `null`, the function returns `null`.
 
diff --git a/docs/reference/query-languages/esql/images/functions/to_aggregate_metric_double.svg b/docs/reference/query-languages/esql/images/functions/to_aggregate_metric_double.svg
deleted file mode 100644
index 12550278d6e36..0000000000000
--- a/docs/reference/query-languages/esql/images/functions/to_aggregate_metric_double.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/to_aggregate_metric_double.json b/docs/reference/query-languages/esql/kibana/definition/functions/to_aggregate_metric_double.json
deleted file mode 100644
index 0336ca89e19e9..0000000000000
--- a/docs/reference/query-languages/esql/kibana/definition/functions/to_aggregate_metric_double.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "comment" : "This is generated by ESQL’s AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.",
-  "type" : "scalar",
-  "name" : "to_aggregate_metric_double",
-  "description" : "Encode a numeric to an aggregate_metric_double.",
-  "signatures" : [ ],
-  "preview" : false,
-  "snapshot_only" : false
-}
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json b/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json
index fdff47a19e369..1b77709586a59 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/to_lower.json
@@ -10,7 +10,7 @@
           "name" : "str",
           "type" : "keyword",
           "optional" : false,
-          "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression."
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
@@ -22,7 +22,7 @@
           "name" : "str",
           "type" : "text",
           "optional" : false,
-          "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression."
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
@@ -30,8 +30,7 @@
     }
   ],
   "examples" : [
-    "ROW message = \"Some Text\"\n| EVAL message_lower = TO_LOWER(message)",
-    "ROW v = TO_LOWER([\"Some\", \"Text\"])"
+    "ROW message = \"Some Text\"\n| EVAL message_lower = TO_LOWER(message)"
   ],
   "preview" : false,
   "snapshot_only" : false
diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json b/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json
index 422830552342c..efd6885ad350a 100644
--- a/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json
+++ b/docs/reference/query-languages/esql/kibana/definition/functions/to_upper.json
@@ -10,7 +10,7 @@
           "name" : "str",
           "type" : "keyword",
           "optional" : false,
-          "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression."
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
@@ -22,7 +22,7 @@
           "name" : "str",
           "type" : "text",
           "optional" : false,
-          "description" : "String expression. If `null`, the function returns `null`. The input can be a single- or multi-valued column or an expression."
+          "description" : "String expression. If `null`, the function returns `null`."
         }
       ],
       "variadic" : false,
diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/to_aggregate_metric_double.md b/docs/reference/query-languages/esql/kibana/docs/functions/to_aggregate_metric_double.md
deleted file mode 100644
index 0dea481d1a773..0000000000000
--- a/docs/reference/query-languages/esql/kibana/docs/functions/to_aggregate_metric_double.md
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-### TO_AGGREGATE_METRIC_DOUBLE
-Encode a numeric to an aggregate_metric_double.
-
diff --git a/x-pack/plugin/esql/build.gradle b/x-pack/plugin/esql/build.gradle
index fcbd72e9bacbd..70210571058be 100644
--- a/x-pack/plugin/esql/build.gradle
+++ b/x-pack/plugin/esql/build.gradle
@@ -167,6 +167,13 @@ tasks.named("test").configure {
 
       List kibana = kibanaTree.files.collect { it.name }
       int countKibana = kibana.size()
+      Closure replaceLinks = line -> {
+        // The kibana docs are not deployed to the normal docs location, so need absolute paths for internal references
+        line.replaceAll(
+          /\]\(\/reference\/([^)\s]+)\.md(#\S+)?\)/,
+          '](https://www.elastic.co/docs/reference/elasticsearch/$1$2)'
+        )
+      }
       if (countKibana == 0) {
         logger.quiet("ESQL Docs: No function/operator kibana docs created. Skipping sync.")
       } else {
@@ -181,6 +188,7 @@ tasks.named("test").configure {
               include '**/*.md', '**/*.json'
             }
           }
+          filter replaceLinks
         }
       }
     }
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec
index 49960d1b5b0f3..4acdbc7cc714c 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec
@@ -218,7 +218,8 @@ emp_no:integer | languages:integer | height:double
 convertToDatePeriod
 required_capability: cast_string_literal_to_temporal_amount
 //tag::castToDatePeriod[]
-row x = "2024-01-01"::datetime | eval y = x + "3 DAYS"::date_period, z = x - to_dateperiod("3 days");
+ROW x = "2024-01-01"::datetime
+| EVAL y = x + "3 DAYS"::date_period, z = x - TO_DATEPERIOD("3 days");
 //end::castToDatePeriod[]
 
 //tag::castToDatePeriod-result[]
@@ -230,7 +231,8 @@ x:datetime |y:datetime |z:datetime
 convertToTimeDuration
 required_capability: cast_string_literal_to_temporal_amount
 //tag::castToTimeDuration[]
-row x = "2024-01-01"::datetime | eval y = x + "3 hours"::time_duration, z = x - to_timeduration("3 hours");
+ROW x = "2024-01-01"::datetime
+| EVAL y = x + "3 hours"::time_duration, z = x - TO_TIMEDURATION("3 hours");
 //end::castToTimeDuration[]
 
 //tag::castToTimeDuration-result[]
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec
index e5cab8de8092b..1689a4f642b59 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec
@@ -344,7 +344,8 @@ null
 
 docsDateDiff#[skip:-8.12.99, reason:date_diff added in 8.13]
 // tag::docsDateDiff[]
-ROW date1 = TO_DATETIME("2023-12-02T11:00:00.000Z"), date2 = TO_DATETIME("2023-12-02T11:00:00.001Z")
+ROW date1 = TO_DATETIME("2023-12-02T11:00:00.000Z"),
+    date2 = TO_DATETIME("2023-12-02T11:00:00.001Z")
 | EVAL dd_ms = DATE_DIFF("microseconds", date1, date2)
 // end::docsDateDiff[]
 ;
@@ -425,12 +426,12 @@ evalDateDiffYearForDocs
 required_capability: date_diff_year_calendarial
 
 // tag::evalDateDiffYearForDocs[]
-ROW end_23=TO_DATETIME("2023-12-31T23:59:59.999Z"),
-  start_24=TO_DATETIME("2024-01-01T00:00:00.000Z"),
-    end_24=TO_DATETIME("2024-12-31T23:59:59.999")
-| EVAL end23_to_start24=DATE_DIFF("year", end_23, start_24)
-| EVAL end23_to_end24=DATE_DIFF("year", end_23, end_24)
-| EVAL start_to_end_24=DATE_DIFF("year", start_24, end_24)
+ROW end_23 = TO_DATETIME("2023-12-31T23:59:59.999Z"),
+  start_24 = TO_DATETIME("2024-01-01T00:00:00.000Z"),
+    end_24 = TO_DATETIME("2024-12-31T23:59:59.999")
+| EVAL end23_to_start24 = DATE_DIFF("year", end_23, start_24)
+| EVAL end23_to_end24   = DATE_DIFF("year", end_23, end_24)
+| EVAL start_to_end_24  = DATE_DIFF("year", start_24, end_24)
 // end::evalDateDiffYearForDocs[]
 ;
 
@@ -1002,7 +1003,8 @@ date:date                 | year:long
 docsDateExtractBusinessHours
 // tag::docsDateExtractBusinessHours[]
 FROM sample_data
-| WHERE DATE_EXTRACT("hour_of_day", @timestamp) < 9 AND DATE_EXTRACT("hour_of_day", @timestamp) >= 17
+| WHERE DATE_EXTRACT("hour_of_day", @timestamp) < 9
+    AND DATE_EXTRACT("hour_of_day", @timestamp) >= 17
 // end::docsDateExtractBusinessHours[]
 ;
 
@@ -1214,16 +1216,20 @@ required_capability: agg_values
 mvAppendDates
 required_capability: fn_mv_append
 
+// tag::mv_append_date[]
 FROM employees
 | WHERE emp_no == 10039 OR emp_no == 10040
 | SORT emp_no
-| EVAL dates = mv_append(birth_date, hire_date)
+| EVAL dates = MV_APPEND(birth_date, hire_date)
 | KEEP emp_no, birth_date, hire_date, dates
+// end::mv_append_date[]
 ;
 
+// tag::mv_append_date-result[]
 emp_no:integer | birth_date:date      | hire_date:date       | dates:date
 10039          | 1959-10-01T00:00:00Z | 1988-01-19T00:00:00Z | [1959-10-01T00:00:00Z, 1988-01-19T00:00:00Z]
 10040          | null                 | 1993-02-14T00:00:00Z | null 
+// end::mv_append_date-result[]
 ;
 
 
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec
index fdc5683d07a99..7fcffb63a30f7 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec
@@ -619,11 +619,19 @@ date nanos less than
 required_capability: to_date_nanos
 required_capability: date_nanos_binary_comparison
 
-FROM date_nanos | WHERE MV_MIN(nanos) < TO_DATE_NANOS("2023-10-23T12:27:28.948Z") AND millis > "2000-01-01" | SORT nanos DESC;
+// tag::to_date_nanos[]
+FROM date_nanos
+| WHERE MV_MIN(nanos) < TO_DATE_NANOS("2023-10-23T12:27:28.948Z")
+    AND millis > "2000-01-01"
+| SORT nanos DESC
+// end::to_date_nanos[]
+;
 
+// tag::to_date_nanos-result[]
 millis:date              | nanos:date_nanos               | num:long
 2023-10-23T12:15:03.360Z | 2023-10-23T12:15:03.360103847Z | 1698063303360103847
 2023-10-23T12:15:03.360Z | 2023-10-23T12:15:03.360103847Z | 1698063303360103847
+// end::to_date_nanos-result[]
 ;
 
 date nanos less than, no mv min
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec
index ac211c1e6c49a..e8d59628c29fc 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec
@@ -548,8 +548,8 @@ beta         | 127.0.0.1
 ipPrefix
 required_capability: fn_ip_prefix
 //tag::ipPrefix[]
-row ip4 = to_ip("1.2.3.4"), ip6 = to_ip("fe80::cae2:65ff:fece:feb9")
-| eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112);
+ROW ip4 = to_ip("1.2.3.4"), ip6 = TO_IP("fe80::cae2:65ff:fece:feb9")
+| EVAL ip4_prefix = IP_PREFIX(ip4, 24, 0), ip6_prefix = IP_PREFIX(ip6, 0, 112);
 //end::ipPrefix[]
 
 //tag::ipPrefix-result[]
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec
index 8ccd78d04e076..757cab264a9e6 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/math.csv-spec
@@ -237,7 +237,7 @@ base: double | value: double | s:double
 ;
 
 logofNegativeValue#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 2.0, value = -2
+ROW base = 2.0, value = -2
 | EVAL s = LOG(base, value);
 
 warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded.
@@ -248,7 +248,7 @@ base: double | value: integer | s:double
 ;
 
 logofNegativeBase#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = -2, value = 2.0
+ROW base = -2, value = 2.0
 | EVAL s = LOG(base, value);
 
 warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded.
@@ -259,7 +259,7 @@ base: integer | value: double | s:double
 ;
 
 logofBaseOne#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 1, value = 2
+ROW base = 1, value = 2
 | EVAL s = LOG(base, value);
 
 warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded.
@@ -270,7 +270,7 @@ base: integer | value: integer | s:double
 ;
 
 logofZero#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 2.0, value = 0.0
+ROW base = 2.0, value = 0.0
 | EVAL s = LOG(base, value);
 
 warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded.
@@ -281,7 +281,7 @@ base:double | value:double | s:double
 ;
 
 logofNegativeZero#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 2.0, value = -0.0
+ROW base = 2.0, value = -0.0
 | EVAL s = LOG(base, value);
 
 warning:Line 2:12: evaluation of [LOG(base, value)] failed, treating result as null. Only first 20 failures recorded.
@@ -292,7 +292,7 @@ base:double | value:double | s:double
 ;
 
 logofIntLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 10, value = to_long(1000000000000)
+ROW base = 10, value = to_long(1000000000000)
 | EVAL s = LOG(base, value);
 
 base:integer | value:long      | s:double
@@ -300,7 +300,7 @@ base:integer | value:long      | s:double
 ;
 
 logofLongInt#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_long(1000000000000), value = 10
+ROW base = to_long(1000000000000), value = 10
 | EVAL s = LOG(base, value);
 
 base:long             | value:integer | s:double
@@ -308,7 +308,7 @@ base:long             | value:integer | s:double
 ;
 
 logofLongLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_long(1000000000000), value = to_long(1000000000000)
+ROW base = to_long(1000000000000), value = to_long(1000000000000)
 | EVAL s = LOG(base, value);
 
 base:long      | value:long     | s:double
@@ -316,7 +316,7 @@ base:long      | value:long     | s:double
 ;
 
 logofLongDouble#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_long(1000000000000), value = 10.0
+ROW base = to_long(1000000000000), value = 10.0
 | EVAL s = LOG(base, value);
 
 base:long             | value:double | s:double
@@ -324,7 +324,7 @@ base:long             | value:double | s:double
 ;
 
 logofDoubleLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 10.0, value = to_long(1000000000000)
+ROW base = 10.0, value = to_long(1000000000000)
 | EVAL s = LOG(base, value);
 
 base:double | value:long     | s:double
@@ -332,7 +332,7 @@ base:double | value:long     | s:double
 ;
 
 logofLongUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_long(1000000000000), value = to_ul(1000000000000000000)
+ROW base = to_long(1000000000000), value = to_ul(1000000000000000000)
 | EVAL s = LOG(base, value);
 
 base:long     | value:UNSIGNED_LONG | s:double
@@ -340,7 +340,7 @@ base:long     | value:UNSIGNED_LONG | s:double
 ;
 
 logofUnsignedLongLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_ul(1000000000000000000), value = to_long(1000000000000)
+ROW base = to_ul(1000000000000000000), value = to_long(1000000000000)
 | EVAL s = LOG(base, value);
 
 base:UNSIGNED_LONG  | value:long     | s:double
@@ -348,7 +348,7 @@ base:UNSIGNED_LONG  | value:long     | s:double
 ;
 
 logofIntUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 10, value = to_ul(1000000000000000000)
+ROW base = 10, value = to_ul(1000000000000000000)
 | EVAL s = LOG(base, value);
 
 base:integer | value:UNSIGNED_LONG | s:double
@@ -356,7 +356,7 @@ base:integer | value:UNSIGNED_LONG | s:double
 ;
 
 logofUnsignedLongInt#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_ul(1000000000000000000), value = 10
+ROW base = to_ul(1000000000000000000), value = 10
 | EVAL s = LOG(base, value);
 
 base:UNSIGNED_LONG  | value:integer | s:double
@@ -364,7 +364,7 @@ base:UNSIGNED_LONG  | value:integer | s:double
 ;
 
 logofUnsignedLongUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_ul(1000000000000000000), value = to_ul(1000000000000000000)
+ROW base = to_ul(1000000000000000000), value = to_ul(1000000000000000000)
 | EVAL s = LOG(base, value);
 
 base:UNSIGNED_LONG  | value:UNSIGNED_LONG | s:double
@@ -372,7 +372,7 @@ base:UNSIGNED_LONG  | value:UNSIGNED_LONG | s:double
 ;
 
 logofUnsignedLongDouble#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = to_ul(1000000000000000000), value = 1000000000.0
+ROW base = to_ul(1000000000000000000), value = 1000000000.0
 | EVAL s = LOG(base, value);
 
 base:UNSIGNED_LONG  | value:double | s:double
@@ -380,7 +380,7 @@ base:UNSIGNED_LONG  | value:double | s:double
 ;
 
 logofDoubleUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row base = 10.0, value = to_ul(1000000000000000000)
+ROW base = 10.0, value = to_ul(1000000000000000000)
 | EVAL s = LOG(base, value);
 
 base:double | value:UNSIGNED_LONG | s:double
@@ -389,7 +389,7 @@ base:double | value:UNSIGNED_LONG | s:double
 
 logofInt#[skip:-8.12.99,reason:new scalar function added in 8.13]
 // tag::logUnary[]
-row value = 100
+ROW value = 100
 | EVAL s = LOG(value);
 // end::logUnary[]
 
@@ -400,7 +400,7 @@ value: integer | s:double
 ;
 
 logofLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row value = to_long(1000000000000)
+ROW value = to_long(1000000000000)
 | EVAL s = LOG(value);
 
 value: long   | s:double
@@ -408,7 +408,7 @@ value: long   | s:double
 ;
 
 logofUnsignedLong#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row value = to_ul(1000000000000000000)
+ROW value = to_ul(1000000000000000000)
 | EVAL s = LOG(value);
 
 value: unsigned_long   | s:double
@@ -416,7 +416,7 @@ value: unsigned_long   | s:double
 ;
 
 logofDouble#[skip:-8.12.99,reason:new scalar function added in 8.13]
-row value = 1000000000000.0
+ROW value = 1000000000000.0
 | EVAL s = LOG(value);
 
 value: double   | s:double
@@ -1323,7 +1323,7 @@ cbrt
 required_capability: fn_cbrt
 // tag::cbrt[]
 ROW d = 1000.0
-| EVAL c = cbrt(d)
+| EVAL c = CBRT(d)
 // end::cbrt[]
 ;
 
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec
index b6c48ac0bb4b9..610baeca91c51 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/stats.csv-spec
@@ -2099,8 +2099,8 @@ FROM employees | STATS min = min(salary) by languages | SORT min + CASE(language
 
 weightedAvg
 required_capability: agg_weighted_avg
-from employees
-| stats w_avg_1 = weighted_avg(salary, 1), avg = avg(salary), w_avg_2 = weighted_avg(salary, height)
+FROM employees
+| STATS w_avg_1 = weighted_avg(salary, 1), avg = avg(salary), w_avg_2 = weighted_avg(salary, height)
 | EVAL w_avg_1 = ROUND(w_avg_1), avg = ROUND(avg), w_avg_2 = ROUND(w_avg_2)
 ;
 
@@ -2112,7 +2112,7 @@ weightedAvgGrouping
 required_capability: agg_weighted_avg
 // tag::weighted-avg[]
 FROM employees
-| STATS w_avg = WEIGHTED_AVG(salary, height) by languages
+| STATS w_avg = WEIGHTED_AVG(salary, height) BY languages
 | EVAL w_avg = ROUND(w_avg)
 | KEEP w_avg, languages
 | SORT languages
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec
index 0019e22fce482..dc15644d927fa 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec
@@ -1722,9 +1722,9 @@ valuesGrouped
 required_capability: agg_values
 
 // tag::values-grouped[]
-  FROM employees
+FROM employees
 | EVAL first_letter = SUBSTRING(first_name, 0, 1)
-| STATS first_name=MV_SORT(VALUES(first_name)) BY first_letter
+| STATS first_name = MV_SORT(VALUES(first_name)) BY first_letter
 | SORT first_letter
 // end::values-grouped[]
 ;
@@ -1768,8 +1768,8 @@ M              | [foo, bar]
 
 locate#[skip:-8.13.99,reason:new string function added in 8.14]
 // tag::locate[]
-row a = "hello"
-| eval a_ll = locate(a, "ll")
+ROW a = "hello"
+| EVAL a_ll = LOCATE(a, "ll")
 // end::locate[]
 ;
 
@@ -1960,8 +1960,8 @@ base64Encode#[skip:-8.13.99,reason:new base64 function added in 8.14]
 required_capability: base64_decode_encode
 
 // tag::to_base64[]
-row a = "elastic" 
-| eval e = to_base64(a)
+ROW a = "elastic" 
+| EVAL e = TO_BASE64(a)
 // end::to_base64[]
 ;
 
@@ -1975,8 +1975,8 @@ base64Decode#[skip:-8.13.99,reason:new base64 function added in 8.14]
 required_capability: base64_decode_encode
 
 // tag::from_base64[]
-row a = "ZWxhc3RpYw=="
-| eval d = from_base64(a)
+ROW a = "ZWxhc3RpYw=="
+| EVAL d = FROM_BASE64(a)
 // end::from_base64[]
 ;
 
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 6677b757c8c6a..40b1b2b106d22 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
@@ -479,18 +479,20 @@ public static class ArgSignature {
         protected final String[] type;
         protected final String description;
         protected final boolean optional;
+        protected final boolean variadic;
         protected final DataType targetDataType;
 
-        public ArgSignature(String name, String[] type, String description, boolean optional, DataType targetDataType) {
+        public ArgSignature(String name, String[] type, String description, boolean optional, boolean variadic, DataType targetDataType) {
             this.name = name;
             this.type = type;
             this.description = description;
             this.optional = optional;
+            this.variadic = variadic;
             this.targetDataType = targetDataType;
         }
 
-        public ArgSignature(String name, String[] type, String description, boolean optional) {
-            this(name, type, description, optional, UNSUPPORTED);
+        public ArgSignature(String name, String[] type, String description, boolean optional, boolean variadic) {
+            this(name, type, description, optional, variadic, UNSUPPORTED);
         }
 
         public String name() {
@@ -542,7 +544,7 @@ public static class MapArgSignature extends ArgSignature {
         private final Map mapParams;
 
         public MapArgSignature(String name, String description, boolean optional, Map mapParams) {
-            super(name, new String[] { "map" }, description, optional);
+            super(name, new String[] { "map" }, description, optional, false);
             this.mapParams = mapParams;
         }
 
@@ -591,6 +593,13 @@ public List argNames() {
             return args.stream().map(ArgSignature::name).toList();
         }
 
+        /**
+         * The signature of every argument.
+         */
+        public List args() {
+            return args;
+        }
+
         /**
          * The description of every argument.
          */
@@ -636,24 +645,25 @@ public static FunctionDescription description(FunctionDefinition def) {
         boolean variadic = false;
         for (int i = 1; i < params.length; i++) { // skipping 1st argument, the source
             if (Configuration.class.isAssignableFrom(params[i].getType()) == false) {
-                variadic |= List.class.isAssignableFrom(params[i].getType());
+                boolean isList = List.class.isAssignableFrom(params[i].getType());
+                variadic |= isList;
                 MapParam mapParamInfo = params[i].getAnnotation(MapParam.class); // refactor this
                 if (mapParamInfo != null) {
                     args.add(mapParam(mapParamInfo));
                 } else {
                     Param paramInfo = params[i].getAnnotation(Param.class);
-                    args.add(paramInfo != null ? param(paramInfo) : paramWithoutAnnotation(params[i].getName()));
+                    args.add(paramInfo != null ? param(paramInfo, isList) : paramWithoutAnnotation(params[i].getName()));
                 }
             }
         }
         return new FunctionDescription(def.name(), args, returnType, functionDescription, variadic, functionInfo.type());
     }
 
-    public static ArgSignature param(Param param) {
+    public static ArgSignature param(Param param, boolean variadic) {
         String[] type = removeUnderConstruction(param.type());
         String desc = param.description().replace('\n', ' ');
         DataType targetDataType = getTargetType(type);
-        return new EsqlFunctionRegistry.ArgSignature(param.name(), type, desc, param.optional(), targetDataType);
+        return new EsqlFunctionRegistry.ArgSignature(param.name(), type, desc, param.optional(), variadic, targetDataType);
     }
 
     public static ArgSignature mapParam(MapParam mapParam) {
@@ -671,7 +681,7 @@ public static ArgSignature mapParam(MapParam mapParam) {
     }
 
     public static ArgSignature paramWithoutAnnotation(String name) {
-        return new EsqlFunctionRegistry.ArgSignature(name, new String[] { "?" }, "", false, UNSUPPORTED);
+        return new EsqlFunctionRegistry.ArgSignature(name, new String[] { "?" }, "", false, false, UNSUPPORTED);
     }
 
     /**
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesTo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesTo.java
new file mode 100644
index 0000000000000..8d9fae9761935
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesTo.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.xpack.esql.expression.function;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FunctionAppliesTo {
+    FunctionAppliesToLifecycle lifeCycle() default FunctionAppliesToLifecycle.GA;
+
+    String version() default "";
+
+    String description() default "";
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesToLifecycle.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesToLifecycle.java
new file mode 100644
index 0000000000000..351c6d5b19fd7
--- /dev/null
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionAppliesToLifecycle.java
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+public enum FunctionAppliesToLifecycle {
+    PREVIEW,
+    BETA,
+    DEVELOPMENT,
+    DEPRECATED,
+    COMING,
+    DISCONTINUED,
+    UNAVAILABLE,
+    GA
+}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java
index 5c5c2f26279a0..bcc6f569e514f 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java
@@ -39,6 +39,11 @@
      */
     boolean preview() default false;
 
+    /**
+     * Whether this function applies to particular versions of Elasticsearch.
+     */
+    FunctionAppliesTo[] appliesTo() default {};
+
     /**
      * The description of the function rendered in the docs and kibana's
      * json files that drive their IDE-like experience. These should be
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java
index 3957a926d9ad2..2c76da4974f43 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java
@@ -91,7 +91,7 @@ public class CountDistinct extends AggregateFunction implements OptionalArgument
             algorithm, which counts based on the hashes of the values with some interesting
             properties:
 
-            :::{include} /reference/data-analysis/aggregations/_snippets/search-aggregations-metrics-cardinality-aggregation-explanation.md
+            :::{include} /reference/aggregations/_snippets/search-aggregations-metrics-cardinality-aggregation-explanation.md
             :::
 
             The `COUNT_DISTINCT` function takes an optional second parameter to configure
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java
index b8758d3e3885d..4ac79f57dbc17 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java
@@ -56,7 +56,7 @@ public class Percentile extends NumericAggregate implements SurrogateExpression
         appendix = """
             ### `PERCENTILE` is (usually) approximate [esql-percentile-approximate]
 
-            :::{include} /reference/data-analysis/aggregations/_snippets/search-aggregations-metrics-percentile-aggregation-approximate.md
+            :::{include} /reference/aggregations/_snippets/search-aggregations-metrics-percentile-aggregation-approximate.md
             :::
 
             ::::{warning}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java
index 5e05c3a448295..7cda030d86039 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java
@@ -23,6 +23,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;
@@ -84,7 +86,8 @@ public class Values extends AggregateFunction implements ToAggregator {
             a [Circuit Breaker Error](docs-content://troubleshoot/elasticsearch/circuit-breaker-errors.md).
             ::::""",
         type = FunctionType.AGGREGATE,
-        examples = @Example(file = "string", tag = "values-grouped")
+        examples = @Example(file = "string", tag = "values-grouped"),
+        appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.PREVIEW) }
     )
     public Values(
         Source source,
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 bcb34f46847a5..f640114faa880 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
@@ -32,6 +32,8 @@
 import org.elasticsearch.xpack.esql.core.type.MultiTypeEsField;
 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.MapParam;
 import org.elasticsearch.xpack.esql.expression.function.OptionalArgument;
@@ -156,7 +158,13 @@ public class Match extends FullTextFunction implements OptionalArgument, PostOpt
             `MATCH` returns true if the provided query matches the row.""",
         examples = {
             @Example(file = "match-function", tag = "match-with-field"),
-            @Example(file = "match-function", tag = "match-with-named-function-params") }
+            @Example(file = "match-function", tag = "match-with-named-function-params") },
+        appliesTo = {
+            @FunctionAppliesTo(
+                lifeCycle = FunctionAppliesToLifecycle.COMING,
+                version = "9.1.0",
+                description = "Support for optional named parameters is only available from 9.1.0"
+            ) }
     )
     public Match(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java
index 811b6ff6c6777..d426308eff775 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryString.java
@@ -25,6 +25,8 @@
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.core.type.DataTypeConverter;
 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.MapParam;
 import org.elasticsearch.xpack.esql.expression.function.OptionalArgument;
@@ -116,7 +118,13 @@ public class QueryString extends FullTextFunction implements OptionalArgument {
             + "Returns true if the provided query string matches the row.",
         examples = {
             @Example(file = "qstr-function", tag = "qstr-with-field"),
-            @Example(file = "qstr-function", tag = "qstr-with-options") }
+            @Example(file = "qstr-function", tag = "qstr-with-options") },
+        appliesTo = {
+            @FunctionAppliesTo(
+                lifeCycle = FunctionAppliesToLifecycle.COMING,
+                version = "9.1.0",
+                description = "Support for optional named parameters is only available from 9.1.0"
+            ) }
     )
     public QueryString(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java
index 837475fca7e74..006d3105159f8 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDateNanos.java
@@ -19,6 +19,7 @@
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
 import org.elasticsearch.xpack.esql.core.type.DataTypeConverter;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 
@@ -63,9 +64,10 @@ public class ToDateNanos extends AbstractConvertFunction {
     @FunctionInfo(
         returnType = "date_nanos",
         description = "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, attepting 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."
+        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.",
+        examples = { @Example(file = "date_nanos", tag = "to_date_nanos") }
     )
     public ToDateNanos(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java
index 7ec7d1b9b2eca..c60fb07704e2e 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAppend.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.expression.function.scalar.EsqlScalarFunction;
@@ -65,7 +66,8 @@ public class MvAppend extends EsqlScalarFunction implements EvaluatorMapper {
             "long",
             "unsigned_long",
             "version" },
-        description = "Concatenates values of two multi-value fields."
+        description = "Concatenates values of two multi-value fields.",
+        examples = { @Example(file = "date", tag = "mv_append_date") }
     )
     public MvAppend(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java
index 084afb1b69996..125efc03916ab 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java
@@ -14,6 +14,8 @@
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 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.io.stream.PlanStreamInput;
@@ -27,7 +29,13 @@ public class ToLower extends ChangeCase {
     @FunctionInfo(
         returnType = { "keyword" },
         description = "Returns a new string representing the input string converted to lower case.",
-        examples = @Example(file = "string", tag = "to_lower")
+        examples = @Example(file = "string", tag = "to_lower"),
+        appliesTo = {
+            @FunctionAppliesTo(
+                lifeCycle = FunctionAppliesToLifecycle.COMING,
+                version = "9.1.0",
+                description = "Support for multivalued parameters is only available from 9.1.0"
+            ) }
     )
     public ToLower(
         Source source,
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java
index 4509404754f36..ec8fc8530274b 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java
@@ -14,6 +14,8 @@
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 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.io.stream.PlanStreamInput;
@@ -27,7 +29,13 @@ public class ToUpper extends ChangeCase {
     @FunctionInfo(
         returnType = { "keyword" },
         description = "Returns a new string representing the input string converted to upper case.",
-        examples = @Example(file = "string", tag = "to_upper")
+        examples = @Example(file = "string", tag = "to_upper"),
+        appliesTo = {
+            @FunctionAppliesTo(
+                lifeCycle = FunctionAppliesToLifecycle.COMING,
+                version = "9.1.0",
+                description = "Support for multivalued parameters is only available from 9.1.0"
+            ) }
     )
     public ToUpper(
         Source source,
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
index a5717e26724f7..7fe6bbeddc1de 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
@@ -806,7 +806,7 @@ protected final void assertTypeResolutionFailure(Expression expression) {
      */
     private static Map, DataType> signatures;
 
-    static Map, DataType> signatures(Class> testClass) {
+    public static Map, DataType> signatures(Class> testClass) {
         if (signatures != null && classGeneratingSignatures == testClass) {
             return signatures;
         }
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 904b7f9aef6de..8181281d04f2f 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
@@ -58,6 +58,7 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -67,7 +68,6 @@
 import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.definition;
 import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.functionRegistered;
 import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.shouldHideSignature;
-import static org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase.signatures;
 import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.mapParam;
 import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.param;
 import static org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry.paramWithoutAnnotation;
@@ -78,11 +78,9 @@ public abstract class DocsV3Support {
         "% This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.\n\n";
 
     static final String PREVIEW_CALLOUT = """
-        ::::{warning}
         Do not use on production environments. This functionality is in technical preview and
         may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview
         are not subject to the support SLA of official GA features.
-        ::::
         """;
 
     static FunctionDocsSupport forFunctions(String name, Class> testClass) {
@@ -142,7 +140,8 @@ public static void renderNegatedOperator(
             entry("esql-time-spans", "esql/esql-time-spans.md"),
             entry("esql-limitations", "esql/limitations.md"),
             entry("esql-function-named-params", "esql/esql-syntax.md"),
-            entry("query-dsl-query-string-query", "query-dsl/query-dsl-query-string-query.md")
+            entry("query-dsl-query-string-query", "query-dsl/query-dsl-query-string-query.md"),
+            entry("regexp-syntax", "query-dsl/regexp-syntax.md")
         );
         // Static links to the commands file
         knownCommands = Map.ofEntries(entry("where", "where"), entry("stats-by", "stats"));
@@ -191,7 +190,7 @@ public static void renderNegatedOperator(
         operatorEntry("match_operator", ":", MatchOperator.class, OperatorCategory.SEARCH)
     );
 
-    enum OperatorCategory {
+    public enum OperatorCategory {
         BINARY,
         UNARY,
         LOGICAL,
@@ -201,7 +200,7 @@ enum OperatorCategory {
         SEARCH
     }
 
-    record OperatorConfig(String name, String symbol, Class> clazz, OperatorCategory category, boolean variadic) {}
+    public record OperatorConfig(String name, String symbol, Class> clazz, OperatorCategory category, boolean variadic) {}
 
     private static Map.Entry operatorEntry(
         String name,
@@ -220,13 +219,13 @@ private static Map.Entry operatorEntry(String name, Stri
     protected final String category;
     protected final String name;
     protected final Logger logger;
-    protected final Class> testClass;
+    private final Supplier