You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by ag...@apache.org on 2026/09/28 18:57:55 UTC

(datafusion-comet) branch branch-1.1 updated: docs: [branch-1.1] generate release docs for 1.1.0 (#6344)

This is an automated email from the ASF dual-hosted git repository.

andygrove pushed a commit to branch branch-1.1
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/branch-1.1 by this push:
     new d7eec29bf3 docs: [branch-1.1] generate release docs for 1.1.0 (#6344)
d7eec29bf3 is described below

commit d7eec29bf3b3674c9d3d00cc915ab5c82efb9e69
Author: Andy Grove <ag...@apache.org>
AuthorDate: Mon Sep 28 12:57:49 2026 -0600

    docs: [branch-1.1] generate release docs for 1.1.0 (#6344)
    
    * fix: pin prettier to the latest release in generate-release-docs.sh
    
    CI installs prettier unpinned, so it checks against the newest release,
    while a bare `npx prettier` reuses whatever version is cached locally.
    The two can disagree, and the committed release docs then fail the
    prettier check. Older prettier versions also reformat the content inside
    the cast tables' prettier-ignore block and indent its end markers.
    
    This is the same change that branch-1.0 carries from #5244.
    
    * docs: generate release docs for 1.1.0
---
 dev/generate-release-docs.sh                       |   8 +-
 .../expressions/spark-3.4/aggregate.md             | 100 +++++
 .../compatibility/expressions/spark-3.4/array.md   |  75 ++++
 .../compatibility/expressions/spark-3.4/cast.md    | 249 ++++++++++++
 .../expressions/spark-3.4/datetime.md              | 146 +++++++
 .../compatibility/expressions/spark-3.4/map.md     |  64 +++
 .../compatibility/expressions/spark-3.4/math.md    |  49 +++
 .../compatibility/expressions/spark-3.4/misc.md    |  66 +++
 .../compatibility/expressions/spark-3.4/string.md  | 176 ++++++++
 .../compatibility/expressions/spark-3.4/struct.md  |  52 +++
 .../compatibility/expressions/spark-3.4/url.md     |  23 ++
 .../expressions/spark-3.5/aggregate.md             | 100 +++++
 .../compatibility/expressions/spark-3.5/array.md   |  75 ++++
 .../compatibility/expressions/spark-3.5/cast.md    | 249 ++++++++++++
 .../expressions/spark-3.5/datetime.md              | 146 +++++++
 .../compatibility/expressions/spark-3.5/map.md     |  64 +++
 .../compatibility/expressions/spark-3.5/math.md    |  49 +++
 .../compatibility/expressions/spark-3.5/misc.md    |  72 ++++
 .../compatibility/expressions/spark-3.5/string.md  | 176 ++++++++
 .../compatibility/expressions/spark-3.5/struct.md  |  52 +++
 .../compatibility/expressions/spark-3.5/url.md     |  23 ++
 .../expressions/spark-4.0/aggregate.md             | 109 +++++
 .../compatibility/expressions/spark-4.0/array.md   |  75 ++++
 .../compatibility/expressions/spark-4.0/cast.md    | 249 ++++++++++++
 .../expressions/spark-4.0/datetime.md              | 156 +++++++
 .../compatibility/expressions/spark-4.0/map.md     |  74 ++++
 .../compatibility/expressions/spark-4.0/math.md    |  49 +++
 .../compatibility/expressions/spark-4.0/misc.md    |  72 ++++
 .../compatibility/expressions/spark-4.0/string.md  | 184 +++++++++
 .../compatibility/expressions/spark-4.0/struct.md  |  52 +++
 .../compatibility/expressions/spark-4.0/url.md     |  23 ++
 .../expressions/spark-4.1/aggregate.md             | 109 +++++
 .../compatibility/expressions/spark-4.1/array.md   |  75 ++++
 .../compatibility/expressions/spark-4.1/cast.md    | 249 ++++++++++++
 .../expressions/spark-4.1/datetime.md              | 156 +++++++
 .../compatibility/expressions/spark-4.1/map.md     |  74 ++++
 .../compatibility/expressions/spark-4.1/math.md    |  49 +++
 .../compatibility/expressions/spark-4.1/misc.md    |  72 ++++
 .../compatibility/expressions/spark-4.1/string.md  | 184 +++++++++
 .../compatibility/expressions/spark-4.1/struct.md  |  52 +++
 .../compatibility/expressions/spark-4.1/url.md     |  23 ++
 docs/source/user-guide/latest/configs.md           | 446 +++++++++++++++++++++
 docs/source/user-guide/latest/expressions.md       |  32 +-
 43 files changed, 4561 insertions(+), 17 deletions(-)

diff --git a/dev/generate-release-docs.sh b/dev/generate-release-docs.sh
index e43d27cb3c..d75fb13125 100755
--- a/dev/generate-release-docs.sh
+++ b/dev/generate-release-docs.sh
@@ -71,12 +71,18 @@ done
 # must pass the check. GenerateDocs wraps the config/cast tables in prettier-ignore, but
 # the surrounding generated Markdown is not guaranteed prettier-clean. prettier honors
 # .prettierignore, so excluded pages (e.g. expressions.md) are left untouched.
+#
+# Pin to `@latest` rather than a bare `npx prettier`. CI installs prettier unpinned
+# (`npm install -g prettier`), so it always checks against the newest release, while a
+# bare `npx prettier` silently reuses whatever version happens to be in the local npx
+# cache. Formatting rules change between versions, so the two can disagree and the
+# committed output then fails the Preflight check even though it looked clean locally.
 if ! command -v npx >/dev/null 2>&1; then
   echo "ERROR: npx not found. Install Node/prettier (see docs/source/contributor-guide/development.md)" >&2
   exit 1
 fi
 echo "Formatting generated Markdown with prettier..."
-npx prettier "${LATEST_USER_GUIDE}/**/*.md" --write
+npx --yes prettier@latest "${LATEST_USER_GUIDE}/**/*.md" --write
 
 echo ""
 echo "Done! Generated documentation content in docs/source/user-guide/latest/"
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/aggregate.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/aggregate.md
new file mode 100644
index 0000000000..daf7a9c00a
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/aggregate.md
@@ -0,0 +1,100 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Aggregate Expressions
+
+<!--BEGIN:EXPR_COMPAT[aggregate]-->
+
+## ApproximatePercentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The percentage argument must be a foldable literal.
+- The accuracy argument must be a foldable literal.
+- Only byte, short, int, long, float, and double input types are supported.
+
+## Average
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- YearMonthIntervalType and DayTimeIntervalType inputs are not supported
+
+## CollectSet
+
+The following incompatibilities cause `CollectSet` to fall back to Spark by default. Set `spark.comet.expression.CollectSet.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Before Spark 4.2, Comet deduplicates NaN values (treats `NaN == NaN`) while Spark treats each NaN as a distinct value. Comet treats -0.0 and 0.0 as distinct while Spark treats them as equal. When `spark.comet.exec.strictFloatingPoint=true`, `collect_set` on floating-point types falls back to Spark on those versions unless `spark.comet.expression.CollectSet.allowIncompatible=true` is set.
+
+## First
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## HyperLogLogPlusPlus
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Input type must be boolean, integral, floating-point, decimal, date/time, string, or binary
+- `DecimalType` with precision > 18 is not supported
+- Collated (non-UTF8_BINARY) strings are not supported
+
+## Last
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## MaxBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the maximum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## MinBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the minimum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## Mode
+
+The following incompatibilities cause `Mode` to fall back to Spark by default. Set `spark.comet.expression.Mode.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- mode breaks ties non-deterministically in Spark (the result depends on JVM hash-map iteration order); Comet returns the smallest of the tied values instead (https://github.com/apache/datafusion-comet/issues/3970)
+
+## Percentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- An array of percentages is not supported.
+- The percentage argument must be a literal.
+- A frequency argument is not supported.
+- Descending order in `WITHIN GROUP (ORDER BY ... DESC)` is not supported.
+- Only numeric input types are supported.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/array.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/array.md
new file mode 100644
index 0000000000..7bc6e29957
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/array.md
@@ -0,0 +1,75 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Array Expressions
+
+<!--BEGIN:EXPR_COMPAT[array]-->
+
+## ArrayContains
+
+By default, `ArrayContains` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayContains.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark compares array elements with ordering.equiv, so -0.0 matches +0.0 and all NaNs match each other; Comet's native array_contains compares the raw Arrow values bitwise
+
+## ArrayExcept
+
+By default, `ArrayExcept` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayExcept.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Null handling and ordering may differ from Spark
+
+## ArrayIntersect
+
+By default, `ArrayIntersect` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayIntersect.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Result array element order may differ from Spark when the right array is longer than the left (DataFusion probes the longer side).
+- array_intersect does not propagate non-UTF8_BINARY collations to the output array elements (https://github.com/apache/datafusion-comet/issues/2190)
+
+## ArrayJoin
+
+By default, `ArrayJoin` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayJoin.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- array_join does not propagate non-UTF8_BINARY collations to the output string (https://github.com/apache/datafusion-comet/issues/2190)
+- array_join evaluates its delimiter and null replacement eagerly, while Spark short-circuits past them (https://github.com/apache/datafusion-comet/issues/3178)
+
+## ArraysZip
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all input data types are supported; falls back to Spark for unsupported types
+
+## Sequence
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- date and timestamp element types run through the JVM codegen dispatcher
+- sequence arguments must be literals or column references; other shapes run through the JVM codegen dispatcher to preserve Spark's per-row null short-circuit
+
+## Shuffle
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- shuffle requires a resolved random seed
+
+## SortArray
+
+By default, `SortArray` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.SortArray.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- When `spark.comet.exec.strictFloatingPoint=true`, sorting on floating-point types is not 100% compatible with Spark
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/cast.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/cast.md
new file mode 100644
index 0000000000..54241e629d
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/cast.md
@@ -0,0 +1,249 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Cast
+
+Cast operations in Comet fall into three levels of support:
+
+- **C (Compatible)**: The results match Apache Spark
+- **I (Incompatible)**: Comet's native cast may produce different results from Apache Spark for some inputs. By
+  default, Comet instead runs Spark's own code-generated cast inside the Comet pipeline, so the results match Spark.
+  Setting `spark.comet.expression.Cast.allowIncompatible=true` selects the native cast, but this is not recommended
+  for production use.
+- **U (Unsupported)**: Comet does not provide a native version of this cast, so it runs Spark's own code-generated
+  cast inside the Comet pipeline.
+- **N/A**: Spark does not support this cast.
+
+Incompatible and unsupported casts fall back to Spark only when Comet's codegen dispatcher cannot handle them (for
+example, casts involving `VariantType`) or when `spark.comet.exec.scalaUDF.codegen.enabled=false`.
+
+## ANSI Mode Support
+
+Enabling ANSI mode does not by itself make a cast fall back to Spark or require
+`spark.comet.expression.Cast.allowIncompatible=true`: every cast that Spark permits in ANSI mode has the same support
+level as in legacy mode. See the [ANSI Mode](#ansi-mode) table below for per-pair support, and the
+[Comet Supported Expressions Guide](../../../expressions.md) for more information on the `allowIncompatible` setting.
+
+## Whitespace Trimming in Casts from String
+
+Spark uses two different notions of whitespace when casting from string. Comet reproduces both,
+with one known exception noted below:
+
+| Trim set                               | Cast targets                                                              |
+| -------------------------------------- | ------------------------------------------------------------------------- |
+| Bytes `0x00`-`0x20` and `0x7F` (`DEL`) | `BOOLEAN`, `TINYINT`, `SMALLINT`, `INT`, `BIGINT`, `DATE`, `TIMESTAMP` \* |
+| Bytes `0x00`-`0x20` only               | `FLOAT`, `DOUBLE`, `DECIMAL`                                              |
+
+Neither set includes any non-ASCII whitespace, so padding a value with `U+0085`, `U+00A0`,
+`U+1680`, `U+2000`-`U+200A`, `U+2028`, `U+2029`, `U+202F`, `U+205F` or `U+3000` produces `NULL`
+(or raises under ANSI mode), even though those codepoints are whitespace to Unicode. Whitespace
+inside a value is never trimmed.
+
+\* `CAST(string AS TIMESTAMP)` and `CAST(string AS TIMESTAMP_NTZ)` still trim Unicode whitespace
+in Comet; see [#5149](https://github.com/apache/datafusion-comet/issues/5149).
+
+## String to Decimal
+
+Comet's native `CAST(string AS DECIMAL)` implementation matches Apache Spark's behavior,
+including:
+
+- Leading and trailing bytes `0x00`-`0x20` are trimmed before parsing, matching the
+  `java.lang.String.trim` that Spark applies before handing the value to `BigDecimal`.
+- Null bytes (`\u0000`) at the start or end of a string are therefore trimmed. Null bytes
+  embedded in the middle of a string produce `NULL`.
+- Fullwidth Unicode digits (U+FF10–U+FF19, e.g. `123.45`) are treated as their ASCII
+  equivalents, so `CAST('123.45' AS DECIMAL(10,2))` returns `123.45`.
+- Scientific notation (e.g. `1.23E+5`) is supported.
+- Special values (`inf`, `infinity`, `nan`) produce `NULL`.
+
+## String to Date
+
+Comet's native `CAST(string AS DATE)` implementation matches Apache Spark's behavior for years
+between 262143 BC and 262142 AD. This range limitation comes from the underlying chrono library's
+`NaiveDate` type. Spark itself supports a wider range. All three eval modes (Legacy, ANSI, Try)
+are supported.
+
+Supported input formats match Spark exactly:
+
+- `yyyy`, `yyyy-[m]m`, `yyyy-[m]m-[d]d`
+- Optional `T` suffix with arbitrary trailing text (e.g. `2020-01-01T12:34:56`)
+- Leading/trailing bytes `0x00`-`0x20` and `0x7F` are trimmed
+- Optional sign prefix (`-` for negative years)
+- Leading zeros (e.g. `0002020-01-01` is year 2020)
+
+## Date to Timestamp
+
+Comet's native `CAST(date AS TIMESTAMP)` is compatible with Spark. The cast interprets each
+date as midnight in the session timezone and converts to a UTC epoch value. DST transitions
+are handled correctly, including spring-forward gaps (where midnight may not exist) and
+fall-back ambiguity (where Comet picks the earlier/DST occurrence, matching Spark's
+`LocalDate.atStartOfDay(zoneId)` behavior).
+
+## Date to TimestampNTZ
+
+Comet's native `CAST(date AS TIMESTAMP_NTZ)` is compatible with Spark. The cast is
+timezone-independent: each date is converted to midnight as pure arithmetic
+(`days * 86,400,000,000` microseconds) with no session timezone offset applied. The result
+is the same regardless of the session timezone setting.
+
+## Date to Numeric Types
+
+In Legacy mode, `CAST(date AS INT)`, `CAST(date AS LONG)`, and casts to all other numeric
+types (Boolean, Byte, Short, Float, Double, Decimal) always return `NULL`. Comet handles
+this by short-circuiting to a null literal during query planning, so no native execution
+is needed. In ANSI and Try modes, Spark rejects these casts at analysis time (before
+execution reaches Comet).
+
+## String to Timestamp
+
+Comet's native `CAST(string AS TIMESTAMP)` implementation supports all timestamp formats accepted
+by Apache Spark, including ISO 8601 date-time strings, date-only strings, time-only strings
+(`HH:MM:SS`), embedded timezone offsets (e.g. `+07:30`, `GMT-01:00`, `UTC`), named timezone
+suffixes (e.g. `Europe/Moscow`), and the full Spark timestamp year range
+(-290308 to 294247).
+
+## String to TimestampNTZ
+
+Comet's native `CAST(string AS TIMESTAMP_NTZ)` implementation matches Apache Spark's behavior.
+Unlike `CAST(string AS TIMESTAMP)`, this cast is timezone-independent: any timezone offset in
+the input string (e.g. `+08:00`, `Z`, `UTC`) is silently discarded, and the local date-time
+components are preserved as-is. Time-only strings (e.g. `T12:34:56`, `12:34`) produce `NULL`.
+The result is always a wall-clock timestamp with no timezone conversion or DST adjustment.
+
+## TimestampNTZ Casts
+
+Comet supports the following `TIMESTAMP_NTZ` casts natively:
+
+| Cast                               | Compatible | Notes                                                             |
+| ---------------------------------- | ---------- | ----------------------------------------------------------------- |
+| `CAST(timestamp_ntz AS STRING)`    | Yes        | Formats local time as-is, timezone-independent                    |
+| `CAST(timestamp_ntz AS DATE)`      | Yes        | Extracts the date component, timezone-independent                 |
+| `CAST(timestamp_ntz AS TIMESTAMP)` | Yes        | Interprets NTZ as local time in session TZ, converts to UTC epoch |
+| `CAST(date AS TIMESTAMP_NTZ)`      | Yes        | Pure arithmetic, timezone-independent                             |
+| `CAST(timestamp AS TIMESTAMP_NTZ)` | Yes        | Shifts UTC epoch to local time in session TZ                      |
+| `CAST(string AS TIMESTAMP_NTZ)`    | Yes        | See [String to TimestampNTZ](#string-to-timestampntz) above       |
+
+The NTZ-to-Timestamp and Timestamp-to-NTZ casts are session-timezone-dependent (the session
+timezone determines the UTC offset). All other NTZ casts are timezone-independent and produce
+the same result regardless of the session timezone.
+
+## Date to String
+
+Comet's native `CAST(date AS STRING)` is compatible with Spark. Years below 1000 are
+zero-padded to four digits (e.g. year 999 renders as `0999-01-01`). Years above 9999 are
+rendered without truncation. The cast is timezone-independent.
+
+## Decimal with Negative Scale to String
+
+Casting a `DecimalType` with a negative scale to `StringType` is marked as incompatible when
+`spark.sql.legacy.allowNegativeScaleOfDecimal` is `false` (the default). When that config is
+disabled, Spark cannot create negative-scale decimals, so by default Comet runs Spark's
+code-generated cast instead of the native one.
+
+When `spark.sql.legacy.allowNegativeScaleOfDecimal=true`, the cast is compatible. Comet matches
+Spark's behavior of using Java `BigDecimal.toString()` semantics, which produces scientific
+notation (e.g. a value of 12300 stored as `Decimal(7,-2)` with unscaled value 123 is rendered
+as `"1.23E+4"`).
+
+## Legacy Mode
+
+<!--BEGIN:CAST_LEGACY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | C | N/A |
+| byte | C | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | C | C | - | C | C | C | C | C | C | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | C | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | C | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | C | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_LEGACY_TABLE-->
+
+## Try Mode
+
+<!--BEGIN:CAST_TRY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_TRY_TABLE-->
+
+## ANSI Mode
+
+<!--BEGIN:CAST_ANSI_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_ANSI_TABLE-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/datetime.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/datetime.md
new file mode 100644
index 0000000000..eb77aafe70
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/datetime.md
@@ -0,0 +1,146 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Date/Time Expressions
+
+- **TruncTimestamp (date_trunc)**: In non-UTC sessions the native path is marked Incompatible and
+  routes through the JVM codegen dispatcher by default, producing Spark-identical results. The
+  native path is itself correct for dates within chrono-tz's DST horizon (approximately year 2100;
+  see "Date and Time Functions" below) and can be enabled by setting
+  `spark.comet.expression.TruncTimestamp.allowIncompatible=true`. TimestampNTZ inputs are handled
+  correctly regardless of session timezone (timezone-independent truncation).
+
+## Date and Time Functions
+
+Comet's native implementation of date and time functions may produce different results than Spark for dates
+far in the future (approximately beyond year 2100). This is because Comet uses the chrono-tz library for
+timezone calculations, which has limited support for Daylight Saving Time (DST) rules beyond the IANA
+time zone database's explicit transitions.
+
+For dates within a reasonable range (approximately 1970-2100), Comet's date and time functions are compatible
+with Spark. For dates beyond this range, functions that involve timezone-aware calculations (such as
+`date_trunc` with timezone-aware timestamps) may produce results with incorrect DST offsets.
+
+If you need to process dates far in the future with accurate timezone handling, consider:
+
+- Using timezone-naive types (`timestamp_ntz`) when timezone conversion is not required
+- Falling back to Spark for these specific operations
+
+<!--BEGIN:EXPR_COMPAT[datetime]-->
+
+## ConvertTimezone
+
+By default, `ConvertTimezone` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ConvertTimezone.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## DateFormatClass
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Format strings in a curated allow-list run natively via DataFusion's `to_char` for UTC sessions. Other format strings (including non-literal formats), as well as non-UTC sessions, route through Spark's own `DateFormatClass.doGenCode` via the Arrow-direct codegen dispatcher when `spark.comet.exec.scalaUDF.codegen.enabled=true` (the default). When the codegen dispatcher is disabled the operator falls back to Spark in those cases.
+
+By default, `DateFormatClass` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.DateFormatClass.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-UTC timezones may produce different results than Spark
+
+## Days
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DateType` and `TimestampType` inputs are supported. `TimestampNTZType` is not supported.
+
+## FromUTCTimestamp
+
+By default, `FromUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## FromUnixTime
+
+By default, `FromUnixTime` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUnixTime.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's valid timestamp range differs from Spark (https://github.com/apache/datafusion/issues/16594)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the default datetime format pattern `yyyy-MM-dd HH:mm:ss` is supported
+
+## Hours
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `TimestampType` and `TimestampNTZType` inputs are supported.
+
+## MakeInterval
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Both the default JVM codegen-dispatch path and the native path currently limit the elapsed-time component to about 292 years in either direction. This only affects extreme intervals and is tracked in [#5279](https://github.com/apache/datafusion-comet/issues/5279).
+
+By default, `MakeInterval` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MakeInterval.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- The native implementation converts seconds to `Float64`, which can lose microsecond precision, and stores time in nanoseconds, which overflows for large time components (hours, minutes, seconds) that Spark can represent.
+
+## PreciseTimestampConversion
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only reinterprets between TimestampType/TimestampNTZType and LongType are supported.
+
+## SecondsToTimestamp
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `IntegerType`, `LongType`, `FloatType`, and `DoubleType` inputs are supported. `DecimalType`, `ByteType`, and `ShortType` fall back to Spark.
+
+## ToUTCTimestamp
+
+By default, `ToUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ToUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## TruncDate
+
+By default, `TruncDate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncDate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-literal format strings will throw an exception instead of returning NULL
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week
+
+## TruncTimestamp
+
+By default, `TruncTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces incorrect results when used with non-UTC timezones. Compatible when timezone is UTC. (https://github.com/apache/datafusion-comet/issues/2649)
+- Non-literal format strings will throw an exception instead of returning NULL
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week, day, dd, hour, minute, second, millisecond, microsecond
+
+## UnixTimestamp
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- String inputs, including collated strings, have no native implementation.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/map.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/map.md
new file mode 100644
index 0000000000..20162ae85c
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/map.md
@@ -0,0 +1,64 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Map Expressions
+
+## MapSort (Spark 4.0+)
+
+Spark 4.0 inserts `MapSort` to normalize map values when they appear in shuffle hash partitioning
+keys, in `try_element_at`, and in other contexts where map ordering must be deterministic. Comet
+runs `MapSort` natively, so map shuffle and group-by-on-map stay on Comet under Spark 4.0.
+
+When `spark.comet.exec.strictFloatingPoint=true`, `MapSort` falls back to Spark for maps whose
+keys contain `Float` or `Double`. Arrow's sort uses
+IEEE total ordering for floating-point, which differs from Spark's `Double.compare` semantics for
+`NaN` and `-0.0`.
+
+<!--BEGIN:EXPR_COMPAT[map]-->
+
+## MapFromArrays
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+The following incompatibilities cause `MapFromArrays` to fall back to Spark by default. Set `spark.comet.expression.MapFromArrays.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## MapFromEntries
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+By default, `MapFromEntries` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MapFromEntries.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `BinaryType` is not supported as a map key in `map_from_entries`
+- `BinaryType` is not supported as a map value in `map_from_entries`
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## StringToMap
+
+By default, `StringToMap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringToMap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `spark.sql.legacy.truncateForEmptyRegexSplit` is enabled, so trailing empty split entries may differ from Spark.
+- `str_to_map` does not support non-UTF8_BINARY collations on the input string or delimiters.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/math.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/math.md
new file mode 100644
index 0000000000..4f4829cacf
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/math.md
@@ -0,0 +1,49 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Math Expressions
+
+<!--BEGIN:EXPR_COMPAT[math]-->
+
+## Abs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- `INTERVAL YEAR TO MONTH` and `INTERVAL DAY TO SECOND` inputs
+
+## Rand
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Randn
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Round
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Float and double inputs. Spark rounds them through a BigDecimal built from `java.lang.Double.toString()` rather than from the exact binary value, and that shortened decimal string can round differently than the value it came from
+- Negative-scale decimal inputs, which are only creatable with spark.sql.legacy.allowNegativeScaleOfDecimal=true
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/misc.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/misc.md
new file mode 100644
index 0000000000..f8ea08ff33
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/misc.md
@@ -0,0 +1,66 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Miscellaneous Expressions
+
+<!--BEGIN:EXPR_COMPAT[misc]-->
+
+## CheckOverflow
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DecimalType` is supported
+
+## Literal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for literal values
+
+## MakeDecimal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `LongType` input is supported
+
+## ScalarSubquery
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for scalar subquery results
+
+## SortOrder
+
+The following incompatibilities cause `SortOrder` to fall back to Spark by default. Set `spark.comet.expression.SortOrder.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Sorting on floating-point values nested in arrays, structs, or maps is not 100% compatible with Spark when `spark.comet.exec.strictFloatingPoint=true`
+
+## StaticInvoke
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Iceberg's `truncate(width, value)` system function on a `decimal` column. Iceberg's TruncateDecimal returns a Decimal that can exceed the column's declared precision, and Spark only turns that into null when the row is materialized. An Arrow Decimal128(precision, scale) array cannot carry that intermediate, so a native kernel would null it during evaluation and change what an enclosing predicate or hash sees. Truncating `-99999999999999.9999` in a `decimal(18,4)` column by a width of 1 [...]
+
+## Uuid
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- uuid requires a resolved random seed
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/string.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/string.md
new file mode 100644
index 0000000000..e6badaa256
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/string.md
@@ -0,0 +1,176 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# String Expressions
+
+<!--BEGIN:EXPR_COMPAT[string]-->
+
+## BitLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## Concat
+
+By default, `Concat` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Concat.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- concat does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- CONCAT supports only string input parameters
+
+## ConcatWs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- all arguments are foldable
+
+## Contains
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## EndsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## GetJsonObject
+
+By default, `GetJsonObject` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.GetJsonObject.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark allows single-quoted JSON and unescaped control characters which Comet does not support
+- For JSON objects containing duplicate keys, Spark returns the value of the first occurrence while Comet's native implementation returns the last occurrence ([#4947](https://github.com/apache/datafusion-comet/issues/4947))
+
+## InitCap
+
+By default, `InitCap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.InitCap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Treats hyphen as a word separator (e.g. `robert rose-smith` produces `Robert Rose-Smith` instead of Spark's `Robert Rose-smith`) (https://github.com/apache/datafusion-comet/issues/1052)
+
+## Levenshtein
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-default (non-UTF8_BINARY) collated input. The native kernel compares raw bytes, so collation-aware comparison has no native path.
+
+## Like
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- LIKE with a custom escape character (only `\` is supported natively)
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## Lower
+
+By default, `Lower` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+## OctetLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## RLike
+
+The following cases use Comet's native implementation by default:
+
+- A `UTF8_BINARY` literal pattern admitted by the [plan-time compatibility analyzer](../../regex.md#when-the-rust-engine-is-safe) is evaluated natively by default.
+
+For applicable cases that are not selected for native execution automatically, `RLike` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline) by default. Set `spark.comet.expression.RLike.allowIncompatible=true` to explicitly select Comet's native implementation, which has the following differences from Spark:
+
+- For applicable literal patterns outside the automatically admitted subset, the native Rust regex engine may behave differently from Java regex.
+
+## RegExpReplace
+
+By default, `RegExpReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.RegExpReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regexp pattern may not be compatible with Spark
+
+## Reverse
+
+By default, `Reverse` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Reverse.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- native reverse does not support arrays whose element type contains binary, struct, or map
+- reverse does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+## StartsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## StringLPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRepeat
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- A negative argument for the number of times to repeat throws an exception instead of returning an empty string as Spark does
+
+## StringReplace
+
+By default, `StringReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces different results from Spark when the search string is empty
+
+## StringSplit
+
+By default, `StringSplit` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringSplit.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regex engine differences between Java and Rust
+
+## StringTranslate
+
+By default, `StringTranslate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringTranslate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's translate iterates over Unicode graphemes (Spark uses code points) and substitutes U+0000 instead of treating it as a deletion sentinel
+
+## UnBase64
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- unbase64 with failOnError = true uses stricter RFC 4648 validation that is not yet implemented natively
+- unbase64 with a non-trivial child expression uses the JVM codegen dispatcher to preserve Spark's short-circuit evaluation (native path is limited to column and literal children)
+
+## Upper
+
+By default, `Upper` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/struct.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/struct.md
new file mode 100644
index 0000000000..c530b12a1a
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/struct.md
@@ -0,0 +1,52 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Struct Expressions
+
+<!--BEGIN:EXPR_COMPAT[struct]-->
+
+## CreateNamedStruct
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `CreateNamedStruct` with duplicate field names is not supported
+
+## JsonToStructs
+
+By default, `JsonToStructs` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.JsonToStructs.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Partially implemented and not comprehensively tested
+
+## StructsToCsv
+
+By default, `StructsToCsv` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToCsv.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Date, Timestamp, TimestampNTZ, and Binary data types may produce different results (https://github.com/apache/datafusion-comet/issues/3232)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Complex types (arrays, maps, structs) in the schema are not supported
+
+## StructsToJson
+
+By default, `StructsToJson` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToJson.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Does not support `+Infinity` and `-Infinity` for numeric types (float, double). (https://github.com/apache/datafusion-comet/issues/3016)
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/url.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/url.md
new file mode 100644
index 0000000000..765e12941f
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.4/url.md
@@ -0,0 +1,23 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# URL Expressions
+
+<!--BEGIN:EXPR_COMPAT[url]-->
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/aggregate.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/aggregate.md
new file mode 100644
index 0000000000..daf7a9c00a
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/aggregate.md
@@ -0,0 +1,100 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Aggregate Expressions
+
+<!--BEGIN:EXPR_COMPAT[aggregate]-->
+
+## ApproximatePercentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The percentage argument must be a foldable literal.
+- The accuracy argument must be a foldable literal.
+- Only byte, short, int, long, float, and double input types are supported.
+
+## Average
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- YearMonthIntervalType and DayTimeIntervalType inputs are not supported
+
+## CollectSet
+
+The following incompatibilities cause `CollectSet` to fall back to Spark by default. Set `spark.comet.expression.CollectSet.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Before Spark 4.2, Comet deduplicates NaN values (treats `NaN == NaN`) while Spark treats each NaN as a distinct value. Comet treats -0.0 and 0.0 as distinct while Spark treats them as equal. When `spark.comet.exec.strictFloatingPoint=true`, `collect_set` on floating-point types falls back to Spark on those versions unless `spark.comet.expression.CollectSet.allowIncompatible=true` is set.
+
+## First
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## HyperLogLogPlusPlus
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Input type must be boolean, integral, floating-point, decimal, date/time, string, or binary
+- `DecimalType` with precision > 18 is not supported
+- Collated (non-UTF8_BINARY) strings are not supported
+
+## Last
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## MaxBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the maximum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## MinBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the minimum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## Mode
+
+The following incompatibilities cause `Mode` to fall back to Spark by default. Set `spark.comet.expression.Mode.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- mode breaks ties non-deterministically in Spark (the result depends on JVM hash-map iteration order); Comet returns the smallest of the tied values instead (https://github.com/apache/datafusion-comet/issues/3970)
+
+## Percentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- An array of percentages is not supported.
+- The percentage argument must be a literal.
+- A frequency argument is not supported.
+- Descending order in `WITHIN GROUP (ORDER BY ... DESC)` is not supported.
+- Only numeric input types are supported.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/array.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/array.md
new file mode 100644
index 0000000000..7bc6e29957
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/array.md
@@ -0,0 +1,75 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Array Expressions
+
+<!--BEGIN:EXPR_COMPAT[array]-->
+
+## ArrayContains
+
+By default, `ArrayContains` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayContains.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark compares array elements with ordering.equiv, so -0.0 matches +0.0 and all NaNs match each other; Comet's native array_contains compares the raw Arrow values bitwise
+
+## ArrayExcept
+
+By default, `ArrayExcept` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayExcept.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Null handling and ordering may differ from Spark
+
+## ArrayIntersect
+
+By default, `ArrayIntersect` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayIntersect.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Result array element order may differ from Spark when the right array is longer than the left (DataFusion probes the longer side).
+- array_intersect does not propagate non-UTF8_BINARY collations to the output array elements (https://github.com/apache/datafusion-comet/issues/2190)
+
+## ArrayJoin
+
+By default, `ArrayJoin` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayJoin.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- array_join does not propagate non-UTF8_BINARY collations to the output string (https://github.com/apache/datafusion-comet/issues/2190)
+- array_join evaluates its delimiter and null replacement eagerly, while Spark short-circuits past them (https://github.com/apache/datafusion-comet/issues/3178)
+
+## ArraysZip
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all input data types are supported; falls back to Spark for unsupported types
+
+## Sequence
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- date and timestamp element types run through the JVM codegen dispatcher
+- sequence arguments must be literals or column references; other shapes run through the JVM codegen dispatcher to preserve Spark's per-row null short-circuit
+
+## Shuffle
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- shuffle requires a resolved random seed
+
+## SortArray
+
+By default, `SortArray` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.SortArray.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- When `spark.comet.exec.strictFloatingPoint=true`, sorting on floating-point types is not 100% compatible with Spark
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/cast.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/cast.md
new file mode 100644
index 0000000000..54241e629d
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/cast.md
@@ -0,0 +1,249 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Cast
+
+Cast operations in Comet fall into three levels of support:
+
+- **C (Compatible)**: The results match Apache Spark
+- **I (Incompatible)**: Comet's native cast may produce different results from Apache Spark for some inputs. By
+  default, Comet instead runs Spark's own code-generated cast inside the Comet pipeline, so the results match Spark.
+  Setting `spark.comet.expression.Cast.allowIncompatible=true` selects the native cast, but this is not recommended
+  for production use.
+- **U (Unsupported)**: Comet does not provide a native version of this cast, so it runs Spark's own code-generated
+  cast inside the Comet pipeline.
+- **N/A**: Spark does not support this cast.
+
+Incompatible and unsupported casts fall back to Spark only when Comet's codegen dispatcher cannot handle them (for
+example, casts involving `VariantType`) or when `spark.comet.exec.scalaUDF.codegen.enabled=false`.
+
+## ANSI Mode Support
+
+Enabling ANSI mode does not by itself make a cast fall back to Spark or require
+`spark.comet.expression.Cast.allowIncompatible=true`: every cast that Spark permits in ANSI mode has the same support
+level as in legacy mode. See the [ANSI Mode](#ansi-mode) table below for per-pair support, and the
+[Comet Supported Expressions Guide](../../../expressions.md) for more information on the `allowIncompatible` setting.
+
+## Whitespace Trimming in Casts from String
+
+Spark uses two different notions of whitespace when casting from string. Comet reproduces both,
+with one known exception noted below:
+
+| Trim set                               | Cast targets                                                              |
+| -------------------------------------- | ------------------------------------------------------------------------- |
+| Bytes `0x00`-`0x20` and `0x7F` (`DEL`) | `BOOLEAN`, `TINYINT`, `SMALLINT`, `INT`, `BIGINT`, `DATE`, `TIMESTAMP` \* |
+| Bytes `0x00`-`0x20` only               | `FLOAT`, `DOUBLE`, `DECIMAL`                                              |
+
+Neither set includes any non-ASCII whitespace, so padding a value with `U+0085`, `U+00A0`,
+`U+1680`, `U+2000`-`U+200A`, `U+2028`, `U+2029`, `U+202F`, `U+205F` or `U+3000` produces `NULL`
+(or raises under ANSI mode), even though those codepoints are whitespace to Unicode. Whitespace
+inside a value is never trimmed.
+
+\* `CAST(string AS TIMESTAMP)` and `CAST(string AS TIMESTAMP_NTZ)` still trim Unicode whitespace
+in Comet; see [#5149](https://github.com/apache/datafusion-comet/issues/5149).
+
+## String to Decimal
+
+Comet's native `CAST(string AS DECIMAL)` implementation matches Apache Spark's behavior,
+including:
+
+- Leading and trailing bytes `0x00`-`0x20` are trimmed before parsing, matching the
+  `java.lang.String.trim` that Spark applies before handing the value to `BigDecimal`.
+- Null bytes (`\u0000`) at the start or end of a string are therefore trimmed. Null bytes
+  embedded in the middle of a string produce `NULL`.
+- Fullwidth Unicode digits (U+FF10–U+FF19, e.g. `123.45`) are treated as their ASCII
+  equivalents, so `CAST('123.45' AS DECIMAL(10,2))` returns `123.45`.
+- Scientific notation (e.g. `1.23E+5`) is supported.
+- Special values (`inf`, `infinity`, `nan`) produce `NULL`.
+
+## String to Date
+
+Comet's native `CAST(string AS DATE)` implementation matches Apache Spark's behavior for years
+between 262143 BC and 262142 AD. This range limitation comes from the underlying chrono library's
+`NaiveDate` type. Spark itself supports a wider range. All three eval modes (Legacy, ANSI, Try)
+are supported.
+
+Supported input formats match Spark exactly:
+
+- `yyyy`, `yyyy-[m]m`, `yyyy-[m]m-[d]d`
+- Optional `T` suffix with arbitrary trailing text (e.g. `2020-01-01T12:34:56`)
+- Leading/trailing bytes `0x00`-`0x20` and `0x7F` are trimmed
+- Optional sign prefix (`-` for negative years)
+- Leading zeros (e.g. `0002020-01-01` is year 2020)
+
+## Date to Timestamp
+
+Comet's native `CAST(date AS TIMESTAMP)` is compatible with Spark. The cast interprets each
+date as midnight in the session timezone and converts to a UTC epoch value. DST transitions
+are handled correctly, including spring-forward gaps (where midnight may not exist) and
+fall-back ambiguity (where Comet picks the earlier/DST occurrence, matching Spark's
+`LocalDate.atStartOfDay(zoneId)` behavior).
+
+## Date to TimestampNTZ
+
+Comet's native `CAST(date AS TIMESTAMP_NTZ)` is compatible with Spark. The cast is
+timezone-independent: each date is converted to midnight as pure arithmetic
+(`days * 86,400,000,000` microseconds) with no session timezone offset applied. The result
+is the same regardless of the session timezone setting.
+
+## Date to Numeric Types
+
+In Legacy mode, `CAST(date AS INT)`, `CAST(date AS LONG)`, and casts to all other numeric
+types (Boolean, Byte, Short, Float, Double, Decimal) always return `NULL`. Comet handles
+this by short-circuiting to a null literal during query planning, so no native execution
+is needed. In ANSI and Try modes, Spark rejects these casts at analysis time (before
+execution reaches Comet).
+
+## String to Timestamp
+
+Comet's native `CAST(string AS TIMESTAMP)` implementation supports all timestamp formats accepted
+by Apache Spark, including ISO 8601 date-time strings, date-only strings, time-only strings
+(`HH:MM:SS`), embedded timezone offsets (e.g. `+07:30`, `GMT-01:00`, `UTC`), named timezone
+suffixes (e.g. `Europe/Moscow`), and the full Spark timestamp year range
+(-290308 to 294247).
+
+## String to TimestampNTZ
+
+Comet's native `CAST(string AS TIMESTAMP_NTZ)` implementation matches Apache Spark's behavior.
+Unlike `CAST(string AS TIMESTAMP)`, this cast is timezone-independent: any timezone offset in
+the input string (e.g. `+08:00`, `Z`, `UTC`) is silently discarded, and the local date-time
+components are preserved as-is. Time-only strings (e.g. `T12:34:56`, `12:34`) produce `NULL`.
+The result is always a wall-clock timestamp with no timezone conversion or DST adjustment.
+
+## TimestampNTZ Casts
+
+Comet supports the following `TIMESTAMP_NTZ` casts natively:
+
+| Cast                               | Compatible | Notes                                                             |
+| ---------------------------------- | ---------- | ----------------------------------------------------------------- |
+| `CAST(timestamp_ntz AS STRING)`    | Yes        | Formats local time as-is, timezone-independent                    |
+| `CAST(timestamp_ntz AS DATE)`      | Yes        | Extracts the date component, timezone-independent                 |
+| `CAST(timestamp_ntz AS TIMESTAMP)` | Yes        | Interprets NTZ as local time in session TZ, converts to UTC epoch |
+| `CAST(date AS TIMESTAMP_NTZ)`      | Yes        | Pure arithmetic, timezone-independent                             |
+| `CAST(timestamp AS TIMESTAMP_NTZ)` | Yes        | Shifts UTC epoch to local time in session TZ                      |
+| `CAST(string AS TIMESTAMP_NTZ)`    | Yes        | See [String to TimestampNTZ](#string-to-timestampntz) above       |
+
+The NTZ-to-Timestamp and Timestamp-to-NTZ casts are session-timezone-dependent (the session
+timezone determines the UTC offset). All other NTZ casts are timezone-independent and produce
+the same result regardless of the session timezone.
+
+## Date to String
+
+Comet's native `CAST(date AS STRING)` is compatible with Spark. Years below 1000 are
+zero-padded to four digits (e.g. year 999 renders as `0999-01-01`). Years above 9999 are
+rendered without truncation. The cast is timezone-independent.
+
+## Decimal with Negative Scale to String
+
+Casting a `DecimalType` with a negative scale to `StringType` is marked as incompatible when
+`spark.sql.legacy.allowNegativeScaleOfDecimal` is `false` (the default). When that config is
+disabled, Spark cannot create negative-scale decimals, so by default Comet runs Spark's
+code-generated cast instead of the native one.
+
+When `spark.sql.legacy.allowNegativeScaleOfDecimal=true`, the cast is compatible. Comet matches
+Spark's behavior of using Java `BigDecimal.toString()` semantics, which produces scientific
+notation (e.g. a value of 12300 stored as `Decimal(7,-2)` with unscaled value 123 is rendered
+as `"1.23E+4"`).
+
+## Legacy Mode
+
+<!--BEGIN:CAST_LEGACY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | C | N/A |
+| byte | C | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | C | C | - | C | C | C | C | C | C | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | C | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | C | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | C | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_LEGACY_TABLE-->
+
+## Try Mode
+
+<!--BEGIN:CAST_TRY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_TRY_TABLE-->
+
+## ANSI Mode
+
+<!--BEGIN:CAST_ANSI_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_ANSI_TABLE-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/datetime.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/datetime.md
new file mode 100644
index 0000000000..eb77aafe70
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/datetime.md
@@ -0,0 +1,146 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Date/Time Expressions
+
+- **TruncTimestamp (date_trunc)**: In non-UTC sessions the native path is marked Incompatible and
+  routes through the JVM codegen dispatcher by default, producing Spark-identical results. The
+  native path is itself correct for dates within chrono-tz's DST horizon (approximately year 2100;
+  see "Date and Time Functions" below) and can be enabled by setting
+  `spark.comet.expression.TruncTimestamp.allowIncompatible=true`. TimestampNTZ inputs are handled
+  correctly regardless of session timezone (timezone-independent truncation).
+
+## Date and Time Functions
+
+Comet's native implementation of date and time functions may produce different results than Spark for dates
+far in the future (approximately beyond year 2100). This is because Comet uses the chrono-tz library for
+timezone calculations, which has limited support for Daylight Saving Time (DST) rules beyond the IANA
+time zone database's explicit transitions.
+
+For dates within a reasonable range (approximately 1970-2100), Comet's date and time functions are compatible
+with Spark. For dates beyond this range, functions that involve timezone-aware calculations (such as
+`date_trunc` with timezone-aware timestamps) may produce results with incorrect DST offsets.
+
+If you need to process dates far in the future with accurate timezone handling, consider:
+
+- Using timezone-naive types (`timestamp_ntz`) when timezone conversion is not required
+- Falling back to Spark for these specific operations
+
+<!--BEGIN:EXPR_COMPAT[datetime]-->
+
+## ConvertTimezone
+
+By default, `ConvertTimezone` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ConvertTimezone.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## DateFormatClass
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Format strings in a curated allow-list run natively via DataFusion's `to_char` for UTC sessions. Other format strings (including non-literal formats), as well as non-UTC sessions, route through Spark's own `DateFormatClass.doGenCode` via the Arrow-direct codegen dispatcher when `spark.comet.exec.scalaUDF.codegen.enabled=true` (the default). When the codegen dispatcher is disabled the operator falls back to Spark in those cases.
+
+By default, `DateFormatClass` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.DateFormatClass.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-UTC timezones may produce different results than Spark
+
+## Days
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DateType` and `TimestampType` inputs are supported. `TimestampNTZType` is not supported.
+
+## FromUTCTimestamp
+
+By default, `FromUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## FromUnixTime
+
+By default, `FromUnixTime` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUnixTime.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's valid timestamp range differs from Spark (https://github.com/apache/datafusion/issues/16594)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the default datetime format pattern `yyyy-MM-dd HH:mm:ss` is supported
+
+## Hours
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `TimestampType` and `TimestampNTZType` inputs are supported.
+
+## MakeInterval
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Both the default JVM codegen-dispatch path and the native path currently limit the elapsed-time component to about 292 years in either direction. This only affects extreme intervals and is tracked in [#5279](https://github.com/apache/datafusion-comet/issues/5279).
+
+By default, `MakeInterval` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MakeInterval.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- The native implementation converts seconds to `Float64`, which can lose microsecond precision, and stores time in nanoseconds, which overflows for large time components (hours, minutes, seconds) that Spark can represent.
+
+## PreciseTimestampConversion
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only reinterprets between TimestampType/TimestampNTZType and LongType are supported.
+
+## SecondsToTimestamp
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `IntegerType`, `LongType`, `FloatType`, and `DoubleType` inputs are supported. `DecimalType`, `ByteType`, and `ShortType` fall back to Spark.
+
+## ToUTCTimestamp
+
+By default, `ToUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ToUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## TruncDate
+
+By default, `TruncDate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncDate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-literal format strings will throw an exception instead of returning NULL
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week
+
+## TruncTimestamp
+
+By default, `TruncTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces incorrect results when used with non-UTC timezones. Compatible when timezone is UTC. (https://github.com/apache/datafusion-comet/issues/2649)
+- Non-literal format strings will throw an exception instead of returning NULL
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week, day, dd, hour, minute, second, millisecond, microsecond
+
+## UnixTimestamp
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- String inputs, including collated strings, have no native implementation.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/map.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/map.md
new file mode 100644
index 0000000000..20162ae85c
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/map.md
@@ -0,0 +1,64 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Map Expressions
+
+## MapSort (Spark 4.0+)
+
+Spark 4.0 inserts `MapSort` to normalize map values when they appear in shuffle hash partitioning
+keys, in `try_element_at`, and in other contexts where map ordering must be deterministic. Comet
+runs `MapSort` natively, so map shuffle and group-by-on-map stay on Comet under Spark 4.0.
+
+When `spark.comet.exec.strictFloatingPoint=true`, `MapSort` falls back to Spark for maps whose
+keys contain `Float` or `Double`. Arrow's sort uses
+IEEE total ordering for floating-point, which differs from Spark's `Double.compare` semantics for
+`NaN` and `-0.0`.
+
+<!--BEGIN:EXPR_COMPAT[map]-->
+
+## MapFromArrays
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+The following incompatibilities cause `MapFromArrays` to fall back to Spark by default. Set `spark.comet.expression.MapFromArrays.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## MapFromEntries
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+By default, `MapFromEntries` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MapFromEntries.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `BinaryType` is not supported as a map key in `map_from_entries`
+- `BinaryType` is not supported as a map value in `map_from_entries`
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## StringToMap
+
+By default, `StringToMap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringToMap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `spark.sql.legacy.truncateForEmptyRegexSplit` is enabled, so trailing empty split entries may differ from Spark.
+- `str_to_map` does not support non-UTF8_BINARY collations on the input string or delimiters.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/math.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/math.md
new file mode 100644
index 0000000000..4f4829cacf
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/math.md
@@ -0,0 +1,49 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Math Expressions
+
+<!--BEGIN:EXPR_COMPAT[math]-->
+
+## Abs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- `INTERVAL YEAR TO MONTH` and `INTERVAL DAY TO SECOND` inputs
+
+## Rand
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Randn
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Round
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Float and double inputs. Spark rounds them through a BigDecimal built from `java.lang.Double.toString()` rather than from the exact binary value, and that shortened decimal string can round differently than the value it came from
+- Negative-scale decimal inputs, which are only creatable with spark.sql.legacy.allowNegativeScaleOfDecimal=true
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/misc.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/misc.md
new file mode 100644
index 0000000000..6c5647a7e5
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/misc.md
@@ -0,0 +1,72 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Miscellaneous Expressions
+
+<!--BEGIN:EXPR_COMPAT[misc]-->
+
+## CheckOverflow
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DecimalType` is supported
+
+## Literal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for literal values
+
+## MakeDecimal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `LongType` input is supported
+
+## ScalarSubquery
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for scalar subquery results
+
+## SortOrder
+
+The following incompatibilities cause `SortOrder` to fall back to Spark by default. Set `spark.comet.expression.SortOrder.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Sorting on floating-point values nested in arrays, structs, or maps is not 100% compatible with Spark when `spark.comet.exec.strictFloatingPoint=true`
+
+## StaticInvoke
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Iceberg's `truncate(width, value)` system function on a `decimal` column. Iceberg's TruncateDecimal returns a Decimal that can exceed the column's declared precision, and Spark only turns that into null when the row is materialized. An Arrow Decimal128(precision, scale) array cannot carry that intermediate, so a native kernel would null it during evaluation and change what an enclosing predicate or hash sees. Truncating `-99999999999999.9999` in a `decimal(18,4)` column by a width of 1 [...]
+
+## ToPrettyString
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Falls back to Spark when the input type cannot be cast to string.
+
+## Uuid
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- uuid requires a resolved random seed
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/string.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/string.md
new file mode 100644
index 0000000000..e6badaa256
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/string.md
@@ -0,0 +1,176 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# String Expressions
+
+<!--BEGIN:EXPR_COMPAT[string]-->
+
+## BitLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## Concat
+
+By default, `Concat` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Concat.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- concat does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- CONCAT supports only string input parameters
+
+## ConcatWs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- all arguments are foldable
+
+## Contains
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## EndsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## GetJsonObject
+
+By default, `GetJsonObject` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.GetJsonObject.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark allows single-quoted JSON and unescaped control characters which Comet does not support
+- For JSON objects containing duplicate keys, Spark returns the value of the first occurrence while Comet's native implementation returns the last occurrence ([#4947](https://github.com/apache/datafusion-comet/issues/4947))
+
+## InitCap
+
+By default, `InitCap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.InitCap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Treats hyphen as a word separator (e.g. `robert rose-smith` produces `Robert Rose-Smith` instead of Spark's `Robert Rose-smith`) (https://github.com/apache/datafusion-comet/issues/1052)
+
+## Levenshtein
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-default (non-UTF8_BINARY) collated input. The native kernel compares raw bytes, so collation-aware comparison has no native path.
+
+## Like
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- LIKE with a custom escape character (only `\` is supported natively)
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## Lower
+
+By default, `Lower` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+## OctetLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## RLike
+
+The following cases use Comet's native implementation by default:
+
+- A `UTF8_BINARY` literal pattern admitted by the [plan-time compatibility analyzer](../../regex.md#when-the-rust-engine-is-safe) is evaluated natively by default.
+
+For applicable cases that are not selected for native execution automatically, `RLike` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline) by default. Set `spark.comet.expression.RLike.allowIncompatible=true` to explicitly select Comet's native implementation, which has the following differences from Spark:
+
+- For applicable literal patterns outside the automatically admitted subset, the native Rust regex engine may behave differently from Java regex.
+
+## RegExpReplace
+
+By default, `RegExpReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.RegExpReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regexp pattern may not be compatible with Spark
+
+## Reverse
+
+By default, `Reverse` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Reverse.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- native reverse does not support arrays whose element type contains binary, struct, or map
+- reverse does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+## StartsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## StringLPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRepeat
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- A negative argument for the number of times to repeat throws an exception instead of returning an empty string as Spark does
+
+## StringReplace
+
+By default, `StringReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces different results from Spark when the search string is empty
+
+## StringSplit
+
+By default, `StringSplit` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringSplit.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regex engine differences between Java and Rust
+
+## StringTranslate
+
+By default, `StringTranslate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringTranslate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's translate iterates over Unicode graphemes (Spark uses code points) and substitutes U+0000 instead of treating it as a deletion sentinel
+
+## UnBase64
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- unbase64 with failOnError = true uses stricter RFC 4648 validation that is not yet implemented natively
+- unbase64 with a non-trivial child expression uses the JVM codegen dispatcher to preserve Spark's short-circuit evaluation (native path is limited to column and literal children)
+
+## Upper
+
+By default, `Upper` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/struct.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/struct.md
new file mode 100644
index 0000000000..c530b12a1a
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/struct.md
@@ -0,0 +1,52 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Struct Expressions
+
+<!--BEGIN:EXPR_COMPAT[struct]-->
+
+## CreateNamedStruct
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `CreateNamedStruct` with duplicate field names is not supported
+
+## JsonToStructs
+
+By default, `JsonToStructs` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.JsonToStructs.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Partially implemented and not comprehensively tested
+
+## StructsToCsv
+
+By default, `StructsToCsv` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToCsv.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Date, Timestamp, TimestampNTZ, and Binary data types may produce different results (https://github.com/apache/datafusion-comet/issues/3232)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Complex types (arrays, maps, structs) in the schema are not supported
+
+## StructsToJson
+
+By default, `StructsToJson` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToJson.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Does not support `+Infinity` and `-Infinity` for numeric types (float, double). (https://github.com/apache/datafusion-comet/issues/3016)
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/url.md b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/url.md
new file mode 100644
index 0000000000..765e12941f
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-3.5/url.md
@@ -0,0 +1,23 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# URL Expressions
+
+<!--BEGIN:EXPR_COMPAT[url]-->
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/aggregate.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/aggregate.md
new file mode 100644
index 0000000000..37fe120ae2
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/aggregate.md
@@ -0,0 +1,109 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Aggregate Expressions
+
+<!--BEGIN:EXPR_COMPAT[aggregate]-->
+
+## ApproximatePercentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The percentage argument must be a foldable literal.
+- The accuracy argument must be a foldable literal.
+- Only byte, short, int, long, float, and double input types are supported.
+
+## Average
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- YearMonthIntervalType and DayTimeIntervalType inputs are not supported
+
+## CollectSet
+
+The following incompatibilities cause `CollectSet` to fall back to Spark by default. Set `spark.comet.expression.CollectSet.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Before Spark 4.2, Comet deduplicates NaN values (treats `NaN == NaN`) while Spark treats each NaN as a distinct value. Comet treats -0.0 and 0.0 as distinct while Spark treats them as equal. When `spark.comet.exec.strictFloatingPoint=true`, `collect_set` on floating-point types falls back to Spark on those versions unless `spark.comet.expression.CollectSet.allowIncompatible=true` is set.
+
+## First
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## HyperLogLogPlusPlus
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Input type must be boolean, integral, floating-point, decimal, date/time, string, or binary
+- `DecimalType` with precision > 18 is not supported
+- Collated (non-UTF8_BINARY) strings are not supported
+
+## Last
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## ListAgg
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` inputs are not supported.
+- `WITHIN GROUP (ORDER BY ...)` is not supported.
+- Non-literal delimiters are not supported.
+- Non-default string collations are not supported.
+
+## MaxBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the maximum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## MinBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the minimum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## Mode
+
+The following incompatibilities cause `Mode` to fall back to Spark by default. Set `spark.comet.expression.Mode.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- mode breaks ties non-deterministically in Spark (the result depends on JVM hash-map iteration order); Comet returns the smallest of the tied values instead (https://github.com/apache/datafusion-comet/issues/3970)
+
+## Percentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- An array of percentages is not supported.
+- The percentage argument must be a literal.
+- A frequency argument is not supported.
+- Descending order in `WITHIN GROUP (ORDER BY ... DESC)` is not supported.
+- Only numeric input types are supported.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/array.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/array.md
new file mode 100644
index 0000000000..7bc6e29957
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/array.md
@@ -0,0 +1,75 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Array Expressions
+
+<!--BEGIN:EXPR_COMPAT[array]-->
+
+## ArrayContains
+
+By default, `ArrayContains` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayContains.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark compares array elements with ordering.equiv, so -0.0 matches +0.0 and all NaNs match each other; Comet's native array_contains compares the raw Arrow values bitwise
+
+## ArrayExcept
+
+By default, `ArrayExcept` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayExcept.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Null handling and ordering may differ from Spark
+
+## ArrayIntersect
+
+By default, `ArrayIntersect` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayIntersect.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Result array element order may differ from Spark when the right array is longer than the left (DataFusion probes the longer side).
+- array_intersect does not propagate non-UTF8_BINARY collations to the output array elements (https://github.com/apache/datafusion-comet/issues/2190)
+
+## ArrayJoin
+
+By default, `ArrayJoin` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayJoin.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- array_join does not propagate non-UTF8_BINARY collations to the output string (https://github.com/apache/datafusion-comet/issues/2190)
+- array_join evaluates its delimiter and null replacement eagerly, while Spark short-circuits past them (https://github.com/apache/datafusion-comet/issues/3178)
+
+## ArraysZip
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all input data types are supported; falls back to Spark for unsupported types
+
+## Sequence
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- date and timestamp element types run through the JVM codegen dispatcher
+- sequence arguments must be literals or column references; other shapes run through the JVM codegen dispatcher to preserve Spark's per-row null short-circuit
+
+## Shuffle
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- shuffle requires a resolved random seed
+
+## SortArray
+
+By default, `SortArray` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.SortArray.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- When `spark.comet.exec.strictFloatingPoint=true`, sorting on floating-point types is not 100% compatible with Spark
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/cast.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/cast.md
new file mode 100644
index 0000000000..54241e629d
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/cast.md
@@ -0,0 +1,249 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Cast
+
+Cast operations in Comet fall into three levels of support:
+
+- **C (Compatible)**: The results match Apache Spark
+- **I (Incompatible)**: Comet's native cast may produce different results from Apache Spark for some inputs. By
+  default, Comet instead runs Spark's own code-generated cast inside the Comet pipeline, so the results match Spark.
+  Setting `spark.comet.expression.Cast.allowIncompatible=true` selects the native cast, but this is not recommended
+  for production use.
+- **U (Unsupported)**: Comet does not provide a native version of this cast, so it runs Spark's own code-generated
+  cast inside the Comet pipeline.
+- **N/A**: Spark does not support this cast.
+
+Incompatible and unsupported casts fall back to Spark only when Comet's codegen dispatcher cannot handle them (for
+example, casts involving `VariantType`) or when `spark.comet.exec.scalaUDF.codegen.enabled=false`.
+
+## ANSI Mode Support
+
+Enabling ANSI mode does not by itself make a cast fall back to Spark or require
+`spark.comet.expression.Cast.allowIncompatible=true`: every cast that Spark permits in ANSI mode has the same support
+level as in legacy mode. See the [ANSI Mode](#ansi-mode) table below for per-pair support, and the
+[Comet Supported Expressions Guide](../../../expressions.md) for more information on the `allowIncompatible` setting.
+
+## Whitespace Trimming in Casts from String
+
+Spark uses two different notions of whitespace when casting from string. Comet reproduces both,
+with one known exception noted below:
+
+| Trim set                               | Cast targets                                                              |
+| -------------------------------------- | ------------------------------------------------------------------------- |
+| Bytes `0x00`-`0x20` and `0x7F` (`DEL`) | `BOOLEAN`, `TINYINT`, `SMALLINT`, `INT`, `BIGINT`, `DATE`, `TIMESTAMP` \* |
+| Bytes `0x00`-`0x20` only               | `FLOAT`, `DOUBLE`, `DECIMAL`                                              |
+
+Neither set includes any non-ASCII whitespace, so padding a value with `U+0085`, `U+00A0`,
+`U+1680`, `U+2000`-`U+200A`, `U+2028`, `U+2029`, `U+202F`, `U+205F` or `U+3000` produces `NULL`
+(or raises under ANSI mode), even though those codepoints are whitespace to Unicode. Whitespace
+inside a value is never trimmed.
+
+\* `CAST(string AS TIMESTAMP)` and `CAST(string AS TIMESTAMP_NTZ)` still trim Unicode whitespace
+in Comet; see [#5149](https://github.com/apache/datafusion-comet/issues/5149).
+
+## String to Decimal
+
+Comet's native `CAST(string AS DECIMAL)` implementation matches Apache Spark's behavior,
+including:
+
+- Leading and trailing bytes `0x00`-`0x20` are trimmed before parsing, matching the
+  `java.lang.String.trim` that Spark applies before handing the value to `BigDecimal`.
+- Null bytes (`\u0000`) at the start or end of a string are therefore trimmed. Null bytes
+  embedded in the middle of a string produce `NULL`.
+- Fullwidth Unicode digits (U+FF10–U+FF19, e.g. `123.45`) are treated as their ASCII
+  equivalents, so `CAST('123.45' AS DECIMAL(10,2))` returns `123.45`.
+- Scientific notation (e.g. `1.23E+5`) is supported.
+- Special values (`inf`, `infinity`, `nan`) produce `NULL`.
+
+## String to Date
+
+Comet's native `CAST(string AS DATE)` implementation matches Apache Spark's behavior for years
+between 262143 BC and 262142 AD. This range limitation comes from the underlying chrono library's
+`NaiveDate` type. Spark itself supports a wider range. All three eval modes (Legacy, ANSI, Try)
+are supported.
+
+Supported input formats match Spark exactly:
+
+- `yyyy`, `yyyy-[m]m`, `yyyy-[m]m-[d]d`
+- Optional `T` suffix with arbitrary trailing text (e.g. `2020-01-01T12:34:56`)
+- Leading/trailing bytes `0x00`-`0x20` and `0x7F` are trimmed
+- Optional sign prefix (`-` for negative years)
+- Leading zeros (e.g. `0002020-01-01` is year 2020)
+
+## Date to Timestamp
+
+Comet's native `CAST(date AS TIMESTAMP)` is compatible with Spark. The cast interprets each
+date as midnight in the session timezone and converts to a UTC epoch value. DST transitions
+are handled correctly, including spring-forward gaps (where midnight may not exist) and
+fall-back ambiguity (where Comet picks the earlier/DST occurrence, matching Spark's
+`LocalDate.atStartOfDay(zoneId)` behavior).
+
+## Date to TimestampNTZ
+
+Comet's native `CAST(date AS TIMESTAMP_NTZ)` is compatible with Spark. The cast is
+timezone-independent: each date is converted to midnight as pure arithmetic
+(`days * 86,400,000,000` microseconds) with no session timezone offset applied. The result
+is the same regardless of the session timezone setting.
+
+## Date to Numeric Types
+
+In Legacy mode, `CAST(date AS INT)`, `CAST(date AS LONG)`, and casts to all other numeric
+types (Boolean, Byte, Short, Float, Double, Decimal) always return `NULL`. Comet handles
+this by short-circuiting to a null literal during query planning, so no native execution
+is needed. In ANSI and Try modes, Spark rejects these casts at analysis time (before
+execution reaches Comet).
+
+## String to Timestamp
+
+Comet's native `CAST(string AS TIMESTAMP)` implementation supports all timestamp formats accepted
+by Apache Spark, including ISO 8601 date-time strings, date-only strings, time-only strings
+(`HH:MM:SS`), embedded timezone offsets (e.g. `+07:30`, `GMT-01:00`, `UTC`), named timezone
+suffixes (e.g. `Europe/Moscow`), and the full Spark timestamp year range
+(-290308 to 294247).
+
+## String to TimestampNTZ
+
+Comet's native `CAST(string AS TIMESTAMP_NTZ)` implementation matches Apache Spark's behavior.
+Unlike `CAST(string AS TIMESTAMP)`, this cast is timezone-independent: any timezone offset in
+the input string (e.g. `+08:00`, `Z`, `UTC`) is silently discarded, and the local date-time
+components are preserved as-is. Time-only strings (e.g. `T12:34:56`, `12:34`) produce `NULL`.
+The result is always a wall-clock timestamp with no timezone conversion or DST adjustment.
+
+## TimestampNTZ Casts
+
+Comet supports the following `TIMESTAMP_NTZ` casts natively:
+
+| Cast                               | Compatible | Notes                                                             |
+| ---------------------------------- | ---------- | ----------------------------------------------------------------- |
+| `CAST(timestamp_ntz AS STRING)`    | Yes        | Formats local time as-is, timezone-independent                    |
+| `CAST(timestamp_ntz AS DATE)`      | Yes        | Extracts the date component, timezone-independent                 |
+| `CAST(timestamp_ntz AS TIMESTAMP)` | Yes        | Interprets NTZ as local time in session TZ, converts to UTC epoch |
+| `CAST(date AS TIMESTAMP_NTZ)`      | Yes        | Pure arithmetic, timezone-independent                             |
+| `CAST(timestamp AS TIMESTAMP_NTZ)` | Yes        | Shifts UTC epoch to local time in session TZ                      |
+| `CAST(string AS TIMESTAMP_NTZ)`    | Yes        | See [String to TimestampNTZ](#string-to-timestampntz) above       |
+
+The NTZ-to-Timestamp and Timestamp-to-NTZ casts are session-timezone-dependent (the session
+timezone determines the UTC offset). All other NTZ casts are timezone-independent and produce
+the same result regardless of the session timezone.
+
+## Date to String
+
+Comet's native `CAST(date AS STRING)` is compatible with Spark. Years below 1000 are
+zero-padded to four digits (e.g. year 999 renders as `0999-01-01`). Years above 9999 are
+rendered without truncation. The cast is timezone-independent.
+
+## Decimal with Negative Scale to String
+
+Casting a `DecimalType` with a negative scale to `StringType` is marked as incompatible when
+`spark.sql.legacy.allowNegativeScaleOfDecimal` is `false` (the default). When that config is
+disabled, Spark cannot create negative-scale decimals, so by default Comet runs Spark's
+code-generated cast instead of the native one.
+
+When `spark.sql.legacy.allowNegativeScaleOfDecimal=true`, the cast is compatible. Comet matches
+Spark's behavior of using Java `BigDecimal.toString()` semantics, which produces scientific
+notation (e.g. a value of 12300 stored as `Decimal(7,-2)` with unscaled value 123 is rendered
+as `"1.23E+4"`).
+
+## Legacy Mode
+
+<!--BEGIN:CAST_LEGACY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | C | N/A |
+| byte | C | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | C | C | - | C | C | C | C | C | C | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | C | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | C | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | C | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_LEGACY_TABLE-->
+
+## Try Mode
+
+<!--BEGIN:CAST_TRY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_TRY_TABLE-->
+
+## ANSI Mode
+
+<!--BEGIN:CAST_ANSI_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_ANSI_TABLE-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/datetime.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/datetime.md
new file mode 100644
index 0000000000..145599e6a7
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/datetime.md
@@ -0,0 +1,156 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Date/Time Expressions
+
+- **TruncTimestamp (date_trunc)**: In non-UTC sessions the native path is marked Incompatible and
+  routes through the JVM codegen dispatcher by default, producing Spark-identical results. The
+  native path is itself correct for dates within chrono-tz's DST horizon (approximately year 2100;
+  see "Date and Time Functions" below) and can be enabled by setting
+  `spark.comet.expression.TruncTimestamp.allowIncompatible=true`. TimestampNTZ inputs are handled
+  correctly regardless of session timezone (timezone-independent truncation).
+
+## Date and Time Functions
+
+Comet's native implementation of date and time functions may produce different results than Spark for dates
+far in the future (approximately beyond year 2100). This is because Comet uses the chrono-tz library for
+timezone calculations, which has limited support for Daylight Saving Time (DST) rules beyond the IANA
+time zone database's explicit transitions.
+
+For dates within a reasonable range (approximately 1970-2100), Comet's date and time functions are compatible
+with Spark. For dates beyond this range, functions that involve timezone-aware calculations (such as
+`date_trunc` with timezone-aware timestamps) may produce results with incorrect DST offsets.
+
+If you need to process dates far in the future with accurate timezone handling, consider:
+
+- Using timezone-naive types (`timestamp_ntz`) when timezone conversion is not required
+- Falling back to Spark for these specific operations
+
+<!--BEGIN:EXPR_COMPAT[datetime]-->
+
+## ConvertTimezone
+
+By default, `ConvertTimezone` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ConvertTimezone.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+- convert_timezone does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+## DateFormatClass
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Format strings in a curated allow-list run natively via DataFusion's `to_char` for UTC sessions. Other format strings (including non-literal formats), as well as non-UTC sessions, route through Spark's own `DateFormatClass.doGenCode` via the Arrow-direct codegen dispatcher when `spark.comet.exec.scalaUDF.codegen.enabled=true` (the default). When the codegen dispatcher is disabled the operator falls back to Spark in those cases.
+
+By default, `DateFormatClass` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.DateFormatClass.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-UTC timezones may produce different results than Spark
+- date_format does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+## Days
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DateType` and `TimestampType` inputs are supported. `TimestampNTZType` is not supported.
+
+## FromUTCTimestamp
+
+By default, `FromUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## FromUnixTime
+
+By default, `FromUnixTime` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUnixTime.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's valid timestamp range differs from Spark (https://github.com/apache/datafusion/issues/16594)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the default datetime format pattern `yyyy-MM-dd HH:mm:ss` is supported
+
+## Hours
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `TimestampType` and `TimestampNTZType` inputs are supported.
+
+## MakeInterval
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Both the default JVM codegen-dispatch path and the native path currently limit the elapsed-time component to about 292 years in either direction. This only affects extreme intervals and is tracked in [#5279](https://github.com/apache/datafusion-comet/issues/5279).
+
+By default, `MakeInterval` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MakeInterval.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- The native implementation converts seconds to `Float64`, which can lose microsecond precision, and stores time in nanoseconds, which overflows for large time components (hours, minutes, seconds) that Spark can represent.
+
+## NextDay
+
+By default, `NextDay` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.NextDay.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- next_day does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+## PreciseTimestampConversion
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only reinterprets between TimestampType/TimestampNTZType and LongType are supported.
+
+## SecondsToTimestamp
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `IntegerType`, `LongType`, `FloatType`, and `DoubleType` inputs are supported. `DecimalType`, `ByteType`, and `ShortType` fall back to Spark.
+
+## ToUTCTimestamp
+
+By default, `ToUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ToUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## TruncDate
+
+By default, `TruncDate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncDate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-literal format strings will throw an exception instead of returning NULL
+- trunc does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week
+
+## TruncTimestamp
+
+By default, `TruncTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces incorrect results when used with non-UTC timezones. Compatible when timezone is UTC. (https://github.com/apache/datafusion-comet/issues/2649)
+- Non-literal format strings will throw an exception instead of returning NULL
+- date_trunc does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week, day, dd, hour, minute, second, millisecond, microsecond
+
+## UnixTimestamp
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- String inputs, including collated strings, have no native implementation.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/map.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/map.md
new file mode 100644
index 0000000000..0fdf312145
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/map.md
@@ -0,0 +1,74 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Map Expressions
+
+## MapSort (Spark 4.0+)
+
+Spark 4.0 inserts `MapSort` to normalize map values when they appear in shuffle hash partitioning
+keys, in `try_element_at`, and in other contexts where map ordering must be deterministic. Comet
+runs `MapSort` natively, so map shuffle and group-by-on-map stay on Comet under Spark 4.0.
+
+When `spark.comet.exec.strictFloatingPoint=true`, `MapSort` falls back to Spark for maps whose
+keys contain `Float` or `Double`. Arrow's sort uses
+IEEE total ordering for floating-point, which differs from Spark's `Double.compare` semantics for
+`NaN` and `-0.0`.
+
+<!--BEGIN:EXPR_COMPAT[map]-->
+
+## MapFromArrays
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+The following incompatibilities cause `MapFromArrays` to fall back to Spark by default. Set `spark.comet.expression.MapFromArrays.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## MapFromEntries
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+By default, `MapFromEntries` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MapFromEntries.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `BinaryType` is not supported as a map key in `map_from_entries`
+- `BinaryType` is not supported as a map value in `map_from_entries`
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## MapSort
+
+The following incompatibilities cause `MapSort` to fall back to Spark by default. Set `spark.comet.expression.MapSort.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- MapSort on floating-point keys is not 100% compatible with Spark when `spark.comet.exec.strictFloatingPoint=true`.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- MapSort is unsupported for non-scalar key types (struct, array, map, etc.).
+
+## StringToMap
+
+By default, `StringToMap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringToMap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `spark.sql.legacy.truncateForEmptyRegexSplit` is enabled, so trailing empty split entries may differ from Spark.
+- `str_to_map` does not support non-UTF8_BINARY collations on the input string or delimiters.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/math.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/math.md
new file mode 100644
index 0000000000..4f4829cacf
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/math.md
@@ -0,0 +1,49 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Math Expressions
+
+<!--BEGIN:EXPR_COMPAT[math]-->
+
+## Abs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- `INTERVAL YEAR TO MONTH` and `INTERVAL DAY TO SECOND` inputs
+
+## Rand
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Randn
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Round
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Float and double inputs. Spark rounds them through a BigDecimal built from `java.lang.Double.toString()` rather than from the exact binary value, and that shortened decimal string can round differently than the value it came from
+- Negative-scale decimal inputs, which are only creatable with spark.sql.legacy.allowNegativeScaleOfDecimal=true
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/misc.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/misc.md
new file mode 100644
index 0000000000..6c5647a7e5
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/misc.md
@@ -0,0 +1,72 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Miscellaneous Expressions
+
+<!--BEGIN:EXPR_COMPAT[misc]-->
+
+## CheckOverflow
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DecimalType` is supported
+
+## Literal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for literal values
+
+## MakeDecimal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `LongType` input is supported
+
+## ScalarSubquery
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for scalar subquery results
+
+## SortOrder
+
+The following incompatibilities cause `SortOrder` to fall back to Spark by default. Set `spark.comet.expression.SortOrder.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Sorting on floating-point values nested in arrays, structs, or maps is not 100% compatible with Spark when `spark.comet.exec.strictFloatingPoint=true`
+
+## StaticInvoke
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Iceberg's `truncate(width, value)` system function on a `decimal` column. Iceberg's TruncateDecimal returns a Decimal that can exceed the column's declared precision, and Spark only turns that into null when the row is materialized. An Arrow Decimal128(precision, scale) array cannot carry that intermediate, so a native kernel would null it during evaluation and change what an enclosing predicate or hash sees. Truncating `-99999999999999.9999` in a `decimal(18,4)` column by a width of 1 [...]
+
+## ToPrettyString
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Falls back to Spark when the input type cannot be cast to string.
+
+## Uuid
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- uuid requires a resolved random seed
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/string.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/string.md
new file mode 100644
index 0000000000..ac08017f6d
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/string.md
@@ -0,0 +1,184 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# String Expressions
+
+<!--BEGIN:EXPR_COMPAT[string]-->
+
+## BitLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## Concat
+
+By default, `Concat` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Concat.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- concat does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- CONCAT supports only string input parameters
+
+## ConcatWs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- all arguments are foldable
+
+## Contains
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## EndsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## GetJsonObject
+
+By default, `GetJsonObject` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.GetJsonObject.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark allows single-quoted JSON and unescaped control characters which Comet does not support
+- For JSON objects containing duplicate keys, Spark returns the value of the first occurrence while Comet's native implementation returns the last occurrence ([#4947](https://github.com/apache/datafusion-comet/issues/4947))
+
+## InitCap
+
+By default, `InitCap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.InitCap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Treats hyphen as a word separator (e.g. `robert rose-smith` produces `Robert Rose-Smith` instead of Spark's `Robert Rose-smith`) (https://github.com/apache/datafusion-comet/issues/1052)
+
+## Levenshtein
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-default (non-UTF8_BINARY) collated input. The native kernel compares raw bytes, so collation-aware comparison has no native path.
+
+## Like
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- LIKE with a custom escape character (only `\` is supported natively)
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## Lower
+
+By default, `Lower` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+## OctetLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## RLike
+
+The following cases use Comet's native implementation by default:
+
+- A `UTF8_BINARY` literal pattern admitted by the [plan-time compatibility analyzer](../../regex.md#when-the-rust-engine-is-safe) is evaluated natively by default.
+
+For applicable cases that are not selected for native execution automatically, `RLike` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline) by default. Set `spark.comet.expression.RLike.allowIncompatible=true` to explicitly select Comet's native implementation, which has the following differences from Spark:
+
+- For applicable literal patterns outside the automatically admitted subset, the native Rust regex engine may behave differently from Java regex.
+
+## RandStr
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `length` must be a literal value
+- `length` must be non-negative
+- `seed` must be a literal value
+
+## RegExpReplace
+
+By default, `RegExpReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.RegExpReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regexp pattern may not be compatible with Spark
+
+## Reverse
+
+By default, `Reverse` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Reverse.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- native reverse does not support arrays whose element type contains binary, struct, or map
+- reverse does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+## StartsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## StringLPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRepeat
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- A negative argument for the number of times to repeat throws an exception instead of returning an empty string as Spark does
+
+## StringReplace
+
+By default, `StringReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces different results from Spark when the search string is empty
+
+## StringSplit
+
+By default, `StringSplit` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringSplit.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regex engine differences between Java and Rust
+
+## StringTranslate
+
+By default, `StringTranslate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringTranslate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's translate iterates over Unicode graphemes (Spark uses code points) and substitutes U+0000 instead of treating it as a deletion sentinel
+
+## UnBase64
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- unbase64 with failOnError = true uses stricter RFC 4648 validation that is not yet implemented natively
+- unbase64 with a non-trivial child expression uses the JVM codegen dispatcher to preserve Spark's short-circuit evaluation (native path is limited to column and literal children)
+
+## Upper
+
+By default, `Upper` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/struct.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/struct.md
new file mode 100644
index 0000000000..c530b12a1a
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/struct.md
@@ -0,0 +1,52 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Struct Expressions
+
+<!--BEGIN:EXPR_COMPAT[struct]-->
+
+## CreateNamedStruct
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `CreateNamedStruct` with duplicate field names is not supported
+
+## JsonToStructs
+
+By default, `JsonToStructs` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.JsonToStructs.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Partially implemented and not comprehensively tested
+
+## StructsToCsv
+
+By default, `StructsToCsv` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToCsv.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Date, Timestamp, TimestampNTZ, and Binary data types may produce different results (https://github.com/apache/datafusion-comet/issues/3232)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Complex types (arrays, maps, structs) in the schema are not supported
+
+## StructsToJson
+
+By default, `StructsToJson` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToJson.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Does not support `+Infinity` and `-Infinity` for numeric types (float, double). (https://github.com/apache/datafusion-comet/issues/3016)
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/url.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/url.md
new file mode 100644
index 0000000000..765e12941f
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.0/url.md
@@ -0,0 +1,23 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# URL Expressions
+
+<!--BEGIN:EXPR_COMPAT[url]-->
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/aggregate.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/aggregate.md
new file mode 100644
index 0000000000..37fe120ae2
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/aggregate.md
@@ -0,0 +1,109 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Aggregate Expressions
+
+<!--BEGIN:EXPR_COMPAT[aggregate]-->
+
+## ApproximatePercentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The percentage argument must be a foldable literal.
+- The accuracy argument must be a foldable literal.
+- Only byte, short, int, long, float, and double input types are supported.
+
+## Average
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- YearMonthIntervalType and DayTimeIntervalType inputs are not supported
+
+## CollectSet
+
+The following incompatibilities cause `CollectSet` to fall back to Spark by default. Set `spark.comet.expression.CollectSet.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Before Spark 4.2, Comet deduplicates NaN values (treats `NaN == NaN`) while Spark treats each NaN as a distinct value. Comet treats -0.0 and 0.0 as distinct while Spark treats them as equal. When `spark.comet.exec.strictFloatingPoint=true`, `collect_set` on floating-point types falls back to Spark on those versions unless `spark.comet.expression.CollectSet.allowIncompatible=true` is set.
+
+## First
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## HyperLogLogPlusPlus
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Input type must be boolean, integral, floating-point, decimal, date/time, string, or binary
+- `DecimalType` with precision > 18 is not supported
+- Collated (non-UTF8_BINARY) strings are not supported
+
+## Last
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is not deterministic. Results may not match Spark.
+
+## ListAgg
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` inputs are not supported.
+- `WITHIN GROUP (ORDER BY ...)` is not supported.
+- Non-literal delimiters are not supported.
+- Non-default string collations are not supported.
+
+## MaxBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the maximum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## MinBy
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- This function is non-deterministic when multiple rows share the minimum ordering value. Results may differ from Spark in that case.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The value and ordering must both be fixed-length types (boolean, integral, floating-point, decimal, date, or timestamp). A variable-length or nested type such as string, binary, or struct falls back to Spark.
+
+## Mode
+
+The following incompatibilities cause `Mode` to fall back to Spark by default. Set `spark.comet.expression.Mode.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- mode breaks ties non-deterministically in Spark (the result depends on JVM hash-map iteration order); Comet returns the smallest of the tied values instead (https://github.com/apache/datafusion-comet/issues/3970)
+
+## Percentile
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- An array of percentages is not supported.
+- The percentage argument must be a literal.
+- A frequency argument is not supported.
+- Descending order in `WITHIN GROUP (ORDER BY ... DESC)` is not supported.
+- Only numeric input types are supported.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/array.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/array.md
new file mode 100644
index 0000000000..7bc6e29957
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/array.md
@@ -0,0 +1,75 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Array Expressions
+
+<!--BEGIN:EXPR_COMPAT[array]-->
+
+## ArrayContains
+
+By default, `ArrayContains` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayContains.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark compares array elements with ordering.equiv, so -0.0 matches +0.0 and all NaNs match each other; Comet's native array_contains compares the raw Arrow values bitwise
+
+## ArrayExcept
+
+By default, `ArrayExcept` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayExcept.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Null handling and ordering may differ from Spark
+
+## ArrayIntersect
+
+By default, `ArrayIntersect` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayIntersect.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Result array element order may differ from Spark when the right array is longer than the left (DataFusion probes the longer side).
+- array_intersect does not propagate non-UTF8_BINARY collations to the output array elements (https://github.com/apache/datafusion-comet/issues/2190)
+
+## ArrayJoin
+
+By default, `ArrayJoin` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ArrayJoin.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- array_join does not propagate non-UTF8_BINARY collations to the output string (https://github.com/apache/datafusion-comet/issues/2190)
+- array_join evaluates its delimiter and null replacement eagerly, while Spark short-circuits past them (https://github.com/apache/datafusion-comet/issues/3178)
+
+## ArraysZip
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all input data types are supported; falls back to Spark for unsupported types
+
+## Sequence
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- date and timestamp element types run through the JVM codegen dispatcher
+- sequence arguments must be literals or column references; other shapes run through the JVM codegen dispatcher to preserve Spark's per-row null short-circuit
+
+## Shuffle
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- shuffle requires a resolved random seed
+
+## SortArray
+
+By default, `SortArray` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.SortArray.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- When `spark.comet.exec.strictFloatingPoint=true`, sorting on floating-point types is not 100% compatible with Spark
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/cast.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/cast.md
new file mode 100644
index 0000000000..54241e629d
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/cast.md
@@ -0,0 +1,249 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Cast
+
+Cast operations in Comet fall into three levels of support:
+
+- **C (Compatible)**: The results match Apache Spark
+- **I (Incompatible)**: Comet's native cast may produce different results from Apache Spark for some inputs. By
+  default, Comet instead runs Spark's own code-generated cast inside the Comet pipeline, so the results match Spark.
+  Setting `spark.comet.expression.Cast.allowIncompatible=true` selects the native cast, but this is not recommended
+  for production use.
+- **U (Unsupported)**: Comet does not provide a native version of this cast, so it runs Spark's own code-generated
+  cast inside the Comet pipeline.
+- **N/A**: Spark does not support this cast.
+
+Incompatible and unsupported casts fall back to Spark only when Comet's codegen dispatcher cannot handle them (for
+example, casts involving `VariantType`) or when `spark.comet.exec.scalaUDF.codegen.enabled=false`.
+
+## ANSI Mode Support
+
+Enabling ANSI mode does not by itself make a cast fall back to Spark or require
+`spark.comet.expression.Cast.allowIncompatible=true`: every cast that Spark permits in ANSI mode has the same support
+level as in legacy mode. See the [ANSI Mode](#ansi-mode) table below for per-pair support, and the
+[Comet Supported Expressions Guide](../../../expressions.md) for more information on the `allowIncompatible` setting.
+
+## Whitespace Trimming in Casts from String
+
+Spark uses two different notions of whitespace when casting from string. Comet reproduces both,
+with one known exception noted below:
+
+| Trim set                               | Cast targets                                                              |
+| -------------------------------------- | ------------------------------------------------------------------------- |
+| Bytes `0x00`-`0x20` and `0x7F` (`DEL`) | `BOOLEAN`, `TINYINT`, `SMALLINT`, `INT`, `BIGINT`, `DATE`, `TIMESTAMP` \* |
+| Bytes `0x00`-`0x20` only               | `FLOAT`, `DOUBLE`, `DECIMAL`                                              |
+
+Neither set includes any non-ASCII whitespace, so padding a value with `U+0085`, `U+00A0`,
+`U+1680`, `U+2000`-`U+200A`, `U+2028`, `U+2029`, `U+202F`, `U+205F` or `U+3000` produces `NULL`
+(or raises under ANSI mode), even though those codepoints are whitespace to Unicode. Whitespace
+inside a value is never trimmed.
+
+\* `CAST(string AS TIMESTAMP)` and `CAST(string AS TIMESTAMP_NTZ)` still trim Unicode whitespace
+in Comet; see [#5149](https://github.com/apache/datafusion-comet/issues/5149).
+
+## String to Decimal
+
+Comet's native `CAST(string AS DECIMAL)` implementation matches Apache Spark's behavior,
+including:
+
+- Leading and trailing bytes `0x00`-`0x20` are trimmed before parsing, matching the
+  `java.lang.String.trim` that Spark applies before handing the value to `BigDecimal`.
+- Null bytes (`\u0000`) at the start or end of a string are therefore trimmed. Null bytes
+  embedded in the middle of a string produce `NULL`.
+- Fullwidth Unicode digits (U+FF10–U+FF19, e.g. `123.45`) are treated as their ASCII
+  equivalents, so `CAST('123.45' AS DECIMAL(10,2))` returns `123.45`.
+- Scientific notation (e.g. `1.23E+5`) is supported.
+- Special values (`inf`, `infinity`, `nan`) produce `NULL`.
+
+## String to Date
+
+Comet's native `CAST(string AS DATE)` implementation matches Apache Spark's behavior for years
+between 262143 BC and 262142 AD. This range limitation comes from the underlying chrono library's
+`NaiveDate` type. Spark itself supports a wider range. All three eval modes (Legacy, ANSI, Try)
+are supported.
+
+Supported input formats match Spark exactly:
+
+- `yyyy`, `yyyy-[m]m`, `yyyy-[m]m-[d]d`
+- Optional `T` suffix with arbitrary trailing text (e.g. `2020-01-01T12:34:56`)
+- Leading/trailing bytes `0x00`-`0x20` and `0x7F` are trimmed
+- Optional sign prefix (`-` for negative years)
+- Leading zeros (e.g. `0002020-01-01` is year 2020)
+
+## Date to Timestamp
+
+Comet's native `CAST(date AS TIMESTAMP)` is compatible with Spark. The cast interprets each
+date as midnight in the session timezone and converts to a UTC epoch value. DST transitions
+are handled correctly, including spring-forward gaps (where midnight may not exist) and
+fall-back ambiguity (where Comet picks the earlier/DST occurrence, matching Spark's
+`LocalDate.atStartOfDay(zoneId)` behavior).
+
+## Date to TimestampNTZ
+
+Comet's native `CAST(date AS TIMESTAMP_NTZ)` is compatible with Spark. The cast is
+timezone-independent: each date is converted to midnight as pure arithmetic
+(`days * 86,400,000,000` microseconds) with no session timezone offset applied. The result
+is the same regardless of the session timezone setting.
+
+## Date to Numeric Types
+
+In Legacy mode, `CAST(date AS INT)`, `CAST(date AS LONG)`, and casts to all other numeric
+types (Boolean, Byte, Short, Float, Double, Decimal) always return `NULL`. Comet handles
+this by short-circuiting to a null literal during query planning, so no native execution
+is needed. In ANSI and Try modes, Spark rejects these casts at analysis time (before
+execution reaches Comet).
+
+## String to Timestamp
+
+Comet's native `CAST(string AS TIMESTAMP)` implementation supports all timestamp formats accepted
+by Apache Spark, including ISO 8601 date-time strings, date-only strings, time-only strings
+(`HH:MM:SS`), embedded timezone offsets (e.g. `+07:30`, `GMT-01:00`, `UTC`), named timezone
+suffixes (e.g. `Europe/Moscow`), and the full Spark timestamp year range
+(-290308 to 294247).
+
+## String to TimestampNTZ
+
+Comet's native `CAST(string AS TIMESTAMP_NTZ)` implementation matches Apache Spark's behavior.
+Unlike `CAST(string AS TIMESTAMP)`, this cast is timezone-independent: any timezone offset in
+the input string (e.g. `+08:00`, `Z`, `UTC`) is silently discarded, and the local date-time
+components are preserved as-is. Time-only strings (e.g. `T12:34:56`, `12:34`) produce `NULL`.
+The result is always a wall-clock timestamp with no timezone conversion or DST adjustment.
+
+## TimestampNTZ Casts
+
+Comet supports the following `TIMESTAMP_NTZ` casts natively:
+
+| Cast                               | Compatible | Notes                                                             |
+| ---------------------------------- | ---------- | ----------------------------------------------------------------- |
+| `CAST(timestamp_ntz AS STRING)`    | Yes        | Formats local time as-is, timezone-independent                    |
+| `CAST(timestamp_ntz AS DATE)`      | Yes        | Extracts the date component, timezone-independent                 |
+| `CAST(timestamp_ntz AS TIMESTAMP)` | Yes        | Interprets NTZ as local time in session TZ, converts to UTC epoch |
+| `CAST(date AS TIMESTAMP_NTZ)`      | Yes        | Pure arithmetic, timezone-independent                             |
+| `CAST(timestamp AS TIMESTAMP_NTZ)` | Yes        | Shifts UTC epoch to local time in session TZ                      |
+| `CAST(string AS TIMESTAMP_NTZ)`    | Yes        | See [String to TimestampNTZ](#string-to-timestampntz) above       |
+
+The NTZ-to-Timestamp and Timestamp-to-NTZ casts are session-timezone-dependent (the session
+timezone determines the UTC offset). All other NTZ casts are timezone-independent and produce
+the same result regardless of the session timezone.
+
+## Date to String
+
+Comet's native `CAST(date AS STRING)` is compatible with Spark. Years below 1000 are
+zero-padded to four digits (e.g. year 999 renders as `0999-01-01`). Years above 9999 are
+rendered without truncation. The cast is timezone-independent.
+
+## Decimal with Negative Scale to String
+
+Casting a `DecimalType` with a negative scale to `StringType` is marked as incompatible when
+`spark.sql.legacy.allowNegativeScaleOfDecimal` is `false` (the default). When that config is
+disabled, Spark cannot create negative-scale decimals, so by default Comet runs Spark's
+code-generated cast instead of the native one.
+
+When `spark.sql.legacy.allowNegativeScaleOfDecimal=true`, the cast is compatible. Comet matches
+Spark's behavior of using Java `BigDecimal.toString()` semantics, which produces scientific
+notation (e.g. a value of 12300 stored as `Decimal(7,-2)` with unscaled value 123 is rendered
+as `"1.23E+4"`).
+
+## Legacy Mode
+
+<!--BEGIN:CAST_LEGACY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | C | N/A |
+| byte | C | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | C | C | - | C | C | C | C | C | C | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | C | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | C | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | C | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_LEGACY_TABLE-->
+
+## Try Mode
+
+<!--BEGIN:CAST_TRY_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_TRY_TABLE-->
+
+## ANSI Mode
+
+<!--BEGIN:CAST_ANSI_TABLE-->
+<!-- prettier-ignore-start -->
+| | binary | boolean | byte | date | decimal | double | float | integer | long | short | string | timestamp | timestamp_ntz |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| binary | - | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | C | N/A | N/A |
+| boolean | N/A | - | C | N/A | U | C | C | C | C | C | C | U | N/A |
+| byte | U | C | - | N/A | C | C | C | C | C | C | C | C | N/A |
+| date | N/A | U | U | - | U | U | U | U | U | U | C | C | C |
+| decimal | N/A | C | C | N/A | - | C | C | C | C | C | C | C | N/A |
+| double | N/A | C | C | N/A | C | - | C | C | C | C | C | C | N/A |
+| float | N/A | C | C | N/A | C | C | - | C | C | C | C | C | N/A |
+| integer | U | C | C | N/A | C | C | C | - | C | C | C | C | N/A |
+| long | U | C | C | N/A | C | C | C | C | - | C | C | C | N/A |
+| short | U | C | C | N/A | C | C | C | C | C | - | C | C | N/A |
+| string | C | C | C | C | C | C | C | C | C | C | - | C | C |
+| timestamp | N/A | U | U | C | U | U | U | U | C | U | C | - | C |
+| timestamp_ntz | N/A | N/A | N/A | C | N/A | N/A | N/A | N/A | N/A | N/A | C | C | - |
+
+**Notes:**
+- **double -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **double -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **float -> decimal**: Rounding matches Spark on JDK 19 and later. On older JDKs, Spark's own result may differ for values whose shortest decimal form falls exactly on a rounding tie
+- **float -> string**: String formatting can differ for floating-point values near precision limits or when scientific notation is used
+- **string -> date**: Only supports years between 262143 BC and 262142 AD
+<!-- prettier-ignore-end -->
+<!--END:CAST_ANSI_TABLE-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/datetime.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/datetime.md
new file mode 100644
index 0000000000..145599e6a7
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/datetime.md
@@ -0,0 +1,156 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Date/Time Expressions
+
+- **TruncTimestamp (date_trunc)**: In non-UTC sessions the native path is marked Incompatible and
+  routes through the JVM codegen dispatcher by default, producing Spark-identical results. The
+  native path is itself correct for dates within chrono-tz's DST horizon (approximately year 2100;
+  see "Date and Time Functions" below) and can be enabled by setting
+  `spark.comet.expression.TruncTimestamp.allowIncompatible=true`. TimestampNTZ inputs are handled
+  correctly regardless of session timezone (timezone-independent truncation).
+
+## Date and Time Functions
+
+Comet's native implementation of date and time functions may produce different results than Spark for dates
+far in the future (approximately beyond year 2100). This is because Comet uses the chrono-tz library for
+timezone calculations, which has limited support for Daylight Saving Time (DST) rules beyond the IANA
+time zone database's explicit transitions.
+
+For dates within a reasonable range (approximately 1970-2100), Comet's date and time functions are compatible
+with Spark. For dates beyond this range, functions that involve timezone-aware calculations (such as
+`date_trunc` with timezone-aware timestamps) may produce results with incorrect DST offsets.
+
+If you need to process dates far in the future with accurate timezone handling, consider:
+
+- Using timezone-naive types (`timestamp_ntz`) when timezone conversion is not required
+- Falling back to Spark for these specific operations
+
+<!--BEGIN:EXPR_COMPAT[datetime]-->
+
+## ConvertTimezone
+
+By default, `ConvertTimezone` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ConvertTimezone.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+- convert_timezone does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+## DateFormatClass
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Format strings in a curated allow-list run natively via DataFusion's `to_char` for UTC sessions. Other format strings (including non-literal formats), as well as non-UTC sessions, route through Spark's own `DateFormatClass.doGenCode` via the Arrow-direct codegen dispatcher when `spark.comet.exec.scalaUDF.codegen.enabled=true` (the default). When the codegen dispatcher is disabled the operator falls back to Spark in those cases.
+
+By default, `DateFormatClass` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.DateFormatClass.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-UTC timezones may produce different results than Spark
+- date_format does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+## Days
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DateType` and `TimestampType` inputs are supported. `TimestampNTZType` is not supported.
+
+## FromUTCTimestamp
+
+By default, `FromUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## FromUnixTime
+
+By default, `FromUnixTime` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.FromUnixTime.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's valid timestamp range differs from Spark (https://github.com/apache/datafusion/issues/16594)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the default datetime format pattern `yyyy-MM-dd HH:mm:ss` is supported
+
+## Hours
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `TimestampType` and `TimestampNTZType` inputs are supported.
+
+## MakeInterval
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Both the default JVM codegen-dispatch path and the native path currently limit the elapsed-time component to about 292 years in either direction. This only affects extreme intervals and is tracked in [#5279](https://github.com/apache/datafusion-comet/issues/5279).
+
+By default, `MakeInterval` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MakeInterval.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- The native implementation converts seconds to `Float64`, which can lose microsecond precision, and stores time in nanoseconds, which overflows for large time components (hours, minutes, seconds) that Spark can represent.
+
+## NextDay
+
+By default, `NextDay` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.NextDay.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- next_day does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+## PreciseTimestampConversion
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only reinterprets between TimestampType/TimestampNTZType and LongType are supported.
+
+## SecondsToTimestamp
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `IntegerType`, `LongType`, `FloatType`, and `DoubleType` inputs are supported. `DecimalType`, `ByteType`, and `ShortType` fall back to Spark.
+
+## ToUTCTimestamp
+
+By default, `ToUTCTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.ToUTCTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Comet's native timezone parser only accepts IANA zone IDs (e.g. `America/Los_Angeles`) and fixed offsets in `+HH:MM` form. Spark also accepts forms such as `GMT+1`, `UTC+1`, or three-letter abbreviations like `PST`; queries using those forms will throw a native parse error at execution time. See https://github.com/apache/datafusion-comet/issues/2013.
+
+## TruncDate
+
+By default, `TruncDate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncDate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Non-literal format strings will throw an exception instead of returning NULL
+- trunc does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week
+
+## TruncTimestamp
+
+By default, `TruncTimestamp` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.TruncTimestamp.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces incorrect results when used with non-UTC timezones. Compatible when timezone is UTC. (https://github.com/apache/datafusion-comet/issues/2649)
+- Non-literal format strings will throw an exception instead of returning NULL
+- date_trunc does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/4646)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Only the following formats are supported: year, yyyy, yy, quarter, mon, month, mm, week, day, dd, hour, minute, second, millisecond, microsecond
+
+## UnixTimestamp
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- String inputs, including collated strings, have no native implementation.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/map.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/map.md
new file mode 100644
index 0000000000..0fdf312145
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/map.md
@@ -0,0 +1,74 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Map Expressions
+
+## MapSort (Spark 4.0+)
+
+Spark 4.0 inserts `MapSort` to normalize map values when they appear in shuffle hash partitioning
+keys, in `try_element_at`, and in other contexts where map ordering must be deterministic. Comet
+runs `MapSort` natively, so map shuffle and group-by-on-map stay on Comet under Spark 4.0.
+
+When `spark.comet.exec.strictFloatingPoint=true`, `MapSort` falls back to Spark for maps whose
+keys contain `Float` or `Double`. Arrow's sort uses
+IEEE total ordering for floating-point, which differs from Spark's `Double.compare` semantics for
+`NaN` and `-0.0`.
+
+<!--BEGIN:EXPR_COMPAT[map]-->
+
+## MapFromArrays
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+The following incompatibilities cause `MapFromArrays` to fall back to Spark by default. Set `spark.comet.expression.MapFromArrays.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## MapFromEntries
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- Spark rejects a `NULL` element inside the keys array with a `RuntimeException` (`Cannot use null as map key`); Comet's native `map_from_arrays` / `map_from_entries` does not detect a per-element `NULL` key and produces a map with a `NULL` key instead ([#4680](https://github.com/apache/datafusion-comet/issues/4680)).
+
+By default, `MapFromEntries` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.MapFromEntries.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `BinaryType` is not supported as a map key in `map_from_entries`
+- `BinaryType` is not supported as a map value in `map_from_entries`
+- `spark.sql.mapKeyDedupPolicy` is set to `LAST_WIN`; Comet's native map construction does not implement LAST_WIN dedup semantics.
+
+## MapSort
+
+The following incompatibilities cause `MapSort` to fall back to Spark by default. Set `spark.comet.expression.MapSort.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- MapSort on floating-point keys is not 100% compatible with Spark when `spark.comet.exec.strictFloatingPoint=true`.
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- MapSort is unsupported for non-scalar key types (struct, array, map, etc.).
+
+## StringToMap
+
+By default, `StringToMap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringToMap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- `spark.sql.legacy.truncateForEmptyRegexSplit` is enabled, so trailing empty split entries may differ from Spark.
+- `str_to_map` does not support non-UTF8_BINARY collations on the input string or delimiters.
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/math.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/math.md
new file mode 100644
index 0000000000..4f4829cacf
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/math.md
@@ -0,0 +1,49 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Math Expressions
+
+<!--BEGIN:EXPR_COMPAT[math]-->
+
+## Abs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- `INTERVAL YEAR TO MONTH` and `INTERVAL DAY TO SECOND` inputs
+
+## Rand
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Randn
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- The `seed` argument must be a literal value
+
+## Round
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Float and double inputs. Spark rounds them through a BigDecimal built from `java.lang.Double.toString()` rather than from the exact binary value, and that shortened decimal string can round differently than the value it came from
+- Negative-scale decimal inputs, which are only creatable with spark.sql.legacy.allowNegativeScaleOfDecimal=true
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/misc.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/misc.md
new file mode 100644
index 0000000000..6c5647a7e5
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/misc.md
@@ -0,0 +1,72 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Miscellaneous Expressions
+
+<!--BEGIN:EXPR_COMPAT[misc]-->
+
+## CheckOverflow
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `DecimalType` is supported
+
+## Literal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for literal values
+
+## MakeDecimal
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Only `LongType` input is supported
+
+## ScalarSubquery
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Not all data types are supported for scalar subquery results
+
+## SortOrder
+
+The following incompatibilities cause `SortOrder` to fall back to Spark by default. Set `spark.comet.expression.SortOrder.allowIncompatible=true` to enable Comet acceleration despite these differences.
+
+- Sorting on floating-point values nested in arrays, structs, or maps is not 100% compatible with Spark when `spark.comet.exec.strictFloatingPoint=true`
+
+## StaticInvoke
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Iceberg's `truncate(width, value)` system function on a `decimal` column. Iceberg's TruncateDecimal returns a Decimal that can exceed the column's declared precision, and Spark only turns that into null when the row is materialized. An Arrow Decimal128(precision, scale) array cannot carry that intermediate, so a native kernel would null it during evaluation and change what an enclosing predicate or hash sees. Truncating `-99999999999999.9999` in a `decimal(18,4)` column by a width of 1 [...]
+
+## ToPrettyString
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- Falls back to Spark when the input type cannot be cast to string.
+
+## Uuid
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- uuid requires a resolved random seed
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/string.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/string.md
new file mode 100644
index 0000000000..ac08017f6d
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/string.md
@@ -0,0 +1,184 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# String Expressions
+
+<!--BEGIN:EXPR_COMPAT[string]-->
+
+## BitLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## Concat
+
+By default, `Concat` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Concat.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- concat does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- CONCAT supports only string input parameters
+
+## ConcatWs
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- all arguments are foldable
+
+## Contains
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## EndsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## GetJsonObject
+
+By default, `GetJsonObject` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.GetJsonObject.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Spark allows single-quoted JSON and unescaped control characters which Comet does not support
+- For JSON objects containing duplicate keys, Spark returns the value of the first occurrence while Comet's native implementation returns the last occurrence ([#4947](https://github.com/apache/datafusion-comet/issues/4947))
+
+## InitCap
+
+By default, `InitCap` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.InitCap.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Treats hyphen as a word separator (e.g. `robert rose-smith` produces `Robert Rose-Smith` instead of Spark's `Robert Rose-smith`) (https://github.com/apache/datafusion-comet/issues/1052)
+
+## Levenshtein
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-default (non-UTF8_BINARY) collated input. The native kernel compares raw bytes, so collation-aware comparison has no native path.
+
+## Like
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- LIKE with a custom escape character (only `\` is supported natively)
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## Lower
+
+By default, `Lower` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+## OctetLength
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `BinaryType` input is not supported
+
+## RLike
+
+The following cases use Comet's native implementation by default:
+
+- A `UTF8_BINARY` literal pattern admitted by the [plan-time compatibility analyzer](../../regex.md#when-the-rust-engine-is-safe) is evaluated natively by default.
+
+For applicable cases that are not selected for native execution automatically, `RLike` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline) by default. Set `spark.comet.expression.RLike.allowIncompatible=true` to explicitly select Comet's native implementation, which has the following differences from Spark:
+
+- For applicable literal patterns outside the automatically admitted subset, the native Rust regex engine may behave differently from Java regex.
+
+## RandStr
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `length` must be a literal value
+- `length` must be non-negative
+- `seed` must be a literal value
+
+## RegExpReplace
+
+By default, `RegExpReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.RegExpReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regexp pattern may not be compatible with Spark
+
+## Reverse
+
+By default, `Reverse` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.Reverse.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- native reverse does not support arrays whose element type contains binary, struct, or map
+- reverse does not support non-UTF8_BINARY collations (https://github.com/apache/datafusion-comet/issues/2190)
+
+## StartsWith
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Non-UTF8_BINARY collated operands are routed through the JVM codegen dispatcher (Spark's own `doGenCode`) because native comparison is byte-wise.
+
+## StringLPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRPad
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Scalar values are not supported for the `str` argument.
+- Only scalar values are supported for the `pad` argument.
+
+## StringRepeat
+
+The following differences from Spark are always present and do not require any additional configuration:
+
+- A negative argument for the number of times to repeat throws an exception instead of returning an empty string as Spark does
+
+## StringReplace
+
+By default, `StringReplace` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringReplace.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Produces different results from Spark when the search string is empty
+
+## StringSplit
+
+By default, `StringSplit` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringSplit.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Regex engine differences between Java and Rust
+
+## StringTranslate
+
+By default, `StringTranslate` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StringTranslate.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- DataFusion's translate iterates over Unicode graphemes (Spark uses code points) and substitutes U+0000 instead of treating it as a deletion sentinel
+
+## UnBase64
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- unbase64 with failOnError = true uses stricter RFC 4648 validation that is not yet implemented natively
+- unbase64 with a non-trivial child expression uses the JVM codegen dispatcher to preserve Spark's short-circuit evaluation (native path is limited to column and literal children)
+
+## Upper
+
+By default, `Upper` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.caseConversion.enabled=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Results can vary depending on locale and character set
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/struct.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/struct.md
new file mode 100644
index 0000000000..c530b12a1a
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/struct.md
@@ -0,0 +1,52 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Struct Expressions
+
+<!--BEGIN:EXPR_COMPAT[struct]-->
+
+## CreateNamedStruct
+
+The following cases are not supported by Comet and always fall back to Spark, regardless of any `allowIncompatible` setting:
+
+- `CreateNamedStruct` with duplicate field names is not supported
+
+## JsonToStructs
+
+By default, `JsonToStructs` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.JsonToStructs.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Partially implemented and not comprehensively tested
+
+## StructsToCsv
+
+By default, `StructsToCsv` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToCsv.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Date, Timestamp, TimestampNTZ, and Binary data types may produce different results (https://github.com/apache/datafusion-comet/issues/3232)
+
+The following cases have no native implementation and always run in the JVM using Spark's code-generated implementation (inside the Comet pipeline):
+
+- Complex types (arrays, maps, structs) in the schema are not supported
+
+## StructsToJson
+
+By default, `StructsToJson` is evaluated in the JVM using Spark's own code-generated implementation (run inside the Comet pipeline), which matches Spark exactly. Set `spark.comet.expression.StructsToJson.allowIncompatible=true` to opt into Comet's native implementation instead, which has the following differences from Spark:
+
+- Does not support `+Infinity` and `-Infinity` for numeric types (float, double). (https://github.com/apache/datafusion-comet/issues/3016)
+
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/url.md b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/url.md
new file mode 100644
index 0000000000..765e12941f
--- /dev/null
+++ b/docs/source/user-guide/latest/compatibility/expressions/spark-4.1/url.md
@@ -0,0 +1,23 @@
+<!---
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# URL Expressions
+
+<!--BEGIN:EXPR_COMPAT[url]-->
+<!--END:EXPR_COMPAT-->
diff --git a/docs/source/user-guide/latest/configs.md b/docs/source/user-guide/latest/configs.md
index 59d5c711fa..035b074593 100644
--- a/docs/source/user-guide/latest/configs.md
+++ b/docs/source/user-guide/latest/configs.md
@@ -24,16 +24,60 @@ Comet provides the following configuration settings.
 ## Scan Configuration Settings
 
 <!--BEGIN:CONFIG_TABLE[scan]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.scan.allowDisabledParquetVectorizedReader` | Whether to allow Comet's native scan to replace the Parquet scan when Spark's spark.sql.parquet.enableVectorizedReader is set to false. By default (false), Comet falls back to Spark in that case, because Comet's native readers mirror Spark's vectorized reader semantics rather than Spark's parquet-mr (non-vectorized) semantics, which permit silent overflow / null-on-narrowing that Comet has no equivalent for. For more information [...]
+| `spark.comet.scan.icebergNative.dataFileConcurrencyLimit` | The number of Iceberg data files to read concurrently within a single task. Higher values improve throughput for tables with many small files by overlapping I/O latency, but increase memory usage. Values between 2 and 8 are suggested. | 1 |
+| `spark.comet.scan.icebergNative.enabled` | Whether to enable native Iceberg table scan using iceberg-rust. When enabled, Iceberg tables are read directly through native execution, bypassing Spark's DataSource V2 API for better performance. | true |
+| `spark.comet.scan.unsignedSmallIntSafetyCheck` | Parquet files may contain unsigned 8-bit integers (UINT_8) which Spark maps to ShortType. When this config is true (default), Comet falls back to Spark for ShortType columns because we cannot distinguish signed INT16 (safe) from unsigned UINT_8 (may produce different results). Set to false to allow native execution of ShortType columns if you know your data does not contain unsigned UINT_8 columns from improperly encoded Parquet files. F [...]
+| `spark.hadoop.fs.comet.libhdfs.schemes` | Defines filesystem schemes (e.g., hdfs, webhdfs) that the native side accesses via libhdfs, separated by commas. Valid only when built with hdfs-opendal feature enabled. | |
+| `spark.hadoop.fs.comet.s3Compliant.schemes` | Defines filesystem schemes (e.g., blob, minio, r2) that Comet treats as S3-compliant, separated by commas. Such schemes reuse the `fs.s3a.*` credential surface and accept vendor-style `fs.<scheme>.<authority>.*` keys. Empty by default, so no alias scheme is claimed unless opted in. Read from the Hadoop configuration, so it must be set before the SparkSession is created. | |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Parquet Reader Configuration Settings
 
 <!--BEGIN:CONFIG_TABLE[parquet]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.parquet.rowFilterPushdown.enabled` | When enabled, the native Parquet reader evaluates pushed filters during decode and lazily materializes projected columns for surviving rows (DataFusion's pushdown_filters / late-materialization). Format-level pruning (row-group statistics, page index, bloom filters) is independent of this flag and runs whenever Spark's spark.sql.parquet.filterPushdown is enabled. Disabling this flag still lets format-level pruning work; the per-row eval [...]
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Query Execution Settings
 
 <!--BEGIN:CONFIG_TABLE[exec]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.caseConversion.enabled` | Java uses locale-specific rules when converting strings to upper or lower case and Rust does not, so we disable upper and lower by default. | false |
+| `spark.comet.convert.csv.enabled` | When enabled, data from Spark (non-native) CSV v1 and v2 scans will be converted to Arrow format. | false |
+| `spark.comet.convert.json.enabled` | When enabled, data from Spark (non-native) JSON v1 and v2 scans will be converted to Arrow format. | false |
+| `spark.comet.convert.parquet.enabled` | When enabled, data from Spark (non-native) Parquet v1 and v2 scans will be converted to Arrow format. | false |
+| `spark.comet.debug.enabled` | Whether to enable debug mode for Comet. When enabled, Comet will do additional checks for debugging purpose. For example, validating array when importing arrays from JVM at native side. Note that these checks may be expensive in performance and should only be enabled for debugging purpose. | false |
+| `spark.comet.enabled` | Whether to enable Comet extension for Spark. When this is turned on, Spark will use Comet to read Parquet data source. Note that to enable native vectorized execution, both this config and `spark.comet.exec.enabled` need to be enabled. It can be overridden by the environment variable `ENABLE_COMET`. | true |
+| `spark.comet.exec.columnarToRow.native.enabled` | Whether to enable native columnar to row conversion. When enabled, Comet will use native Rust code to convert Arrow columnar data to Spark UnsafeRow format instead of the JVM implementation. The native conversion carries a fixed JNI cost per batch and is slower than the JVM implementation for small batches. | false |
+| `spark.comet.exec.enabled` | Whether to enable Comet native vectorized execution for Spark. This controls whether Spark should convert operators into their Comet counterparts and execute them in native space. Note: each operator is associated with a separate config in the format of `spark.comet.exec.<operator_name>.enabled` at the moment, and both the config and this need to be turned on, in order for the operator to be executed in native. | true |
+| `spark.comet.exec.forceShuffledHashJoin` | Experimental feature to force Spark to replace SortMergeJoin with ShuffledHashJoin for improved performance. This feature is not stable yet. For more information, refer to the [Comet Tuning Guide](https://datafusion.apache.org/comet/user-guide/latest/tuning.html). | false |
+| `spark.comet.exec.inMemoryCache.compression.codec` | The Arrow IPC compression codec used when Comet's cache serializer writes cached data. Unlike spark.io.compression.codec, this compresses each Arrow buffer separately rather than the batch as a whole, which is what lets a projected scan decompress only the columns it selected. zstd is the default for footprint rather than speed: it stores cached data in a fraction of the memory, but makes materializing slower, and a read slower in pr [...]
+| `spark.comet.exec.inMemoryCache.compression.zstd.level` | The compression level to use when Comet's cache serializer compresses cached data with zstd. Ignored for other codecs. | 1 |
+| `spark.comet.exec.inMemoryCache.enabled` | Whether to enable Comet native execution for in-memory cached tables. Its value at startup also decides whether CometDriverPlugin installs Comet's cache serializer, which stores cached data in Arrow format. Because spark.sql.cache.serializer is a static config, the cached format is fixed for the application, and disabling this at runtime only sends cached scans back to Spark's execution path. Relations whose schema Comet's Arrow writer does no [...]
+| `spark.comet.exec.join.dynamicFilter.enabled` | Experimental opt-in: use a completed native hash join build's key domain to prune eligible native Parquet row groups and filter probe batches before the hash probe. Supports inner joins with one direct signed integer key and one native partition per input, including both Spark build sides. The probe filter remains active when reader pruning is unavailable. Unsupported joins retain their existing execution path. Filters do not cross Spark  [...]
+| `spark.comet.exec.pyarrowUDF.enabled` | Experimental: whether to enable optimized execution of PyArrow UDFs (mapInArrow/mapInPandas). When enabled, Comet passes Arrow columnar data directly to Python UDFs without the intermediate Arrow-to-Row-to-Arrow conversion that Spark normally performs. Disabled by default while the feature stabilizes. | false |
+| `spark.comet.exec.scalaUDF.codegen.enabled` | Whether to route Spark `ScalaUDF` expressions through Comet's Arrow-direct codegen dispatcher. When enabled, a supported ScalaUDF is compiled into a per-batch kernel that reads and writes Arrow vectors directly from native execution. When disabled, plans containing a ScalaUDF fall back to Spark for the enclosing operator. The same dispatcher backs the regex family (`rlike`, `regexp_replace`, `split`, `regexp_extract`, `regexp_extract_all`,  [...]
+| `spark.comet.exec.strictFloatingPoint` | When enabled, fall back to Spark for floating-point operations that may differ from Spark, such as comparing -0.0 and 0.0, sorting floating-point values nested in arrays, structs, or maps, or sorting the elements of a floating-point array with `sort_array`. Scalar `ORDER BY`, window ordering and range partitioning keys are unaffected, because Comet normalizes those comparison keys to match Spark. For more information, refer to the [Comet Compati [...]
+| `spark.comet.exec.transitionRevert.enabled` | When enabled, Comet reverts a query stage to Spark row-based execution if the number of columnar-to-row (C2R) transitions in the stage exceeds the configured threshold. This avoids the overhead of repeated format conversions in stages where many operators fall back to row-based execution. | false |
+| `spark.comet.exec.transitionRevert.maxTransitions` | The maximum number of columnar-to-row (C2R) transitions allowed in a single query stage before Comet reverts the entire stage to Spark row-based execution. When columnar shuffle is enabled, each such C2R typically implies a corresponding row-to-columnar conversion to feed back into the columnar shuffle, so each counted C2R is a useful proxy for the conversion overhead in the stage. Set to 0 to revert any stage with transitions. Only  [...]
+| `spark.comet.metrics.enabled` | Whether to enable Comet metrics reporting through Spark's external monitoring system. When enabled, Comet exposes metrics such as native operators, Spark operators, queries planned, transitions, and acceleration ratio. These metrics can be visualized through tools like Grafana when a metrics sink (e.g., Prometheus) is configured. Disabled by default because Spark plan traversal adds overhead and metrics require a sink to be useful. This config must be se [...]
+| `spark.comet.metrics.updateInterval` | The interval in milliseconds to update metrics. If interval is negative, metrics will be updated upon task completion. | 3000 |
+| `spark.comet.nativeLoadRequired` | Whether to require Comet native library to load successfully when Comet is enabled. If not, Comet will silently fallback to Spark when it fails to load the native lib. Otherwise, an error will be thrown and the Spark job will be aborted. | false |
+| `spark.comet.operator.DataWritingCommandExec.allowIncompatible` | Whether to allow incompatibility for operator: DataWritingCommandExec. False by default. Can be overridden with SPARK_COMET_OPERATOR_DATAWRITINGCOMMANDEXEC_ALLOWINCOMPATIBLE env variable It can be overridden by the environment variable `SPARK_COMET_OPERATOR_DATAWRITINGCOMMANDEXEC_ALLOWINCOMPATIBLE`. | false |
+| `spark.comet.operator.WriteFilesExec.allowIncompatible` | Whether to allow incompatibility for operator: WriteFilesExec. False by default. Can be overridden with SPARK_COMET_OPERATOR_WRITEFILESEXEC_ALLOWINCOMPATIBLE env variable It can be overridden by the environment variable `SPARK_COMET_OPERATOR_WRITEFILESEXEC_ALLOWINCOMPATIBLE`. | false |
+| `spark.comet.sparkToColumnar.enabled` | Whether to enable Spark to Arrow columnar conversion. When this is turned on, Comet will convert operators in `spark.comet.sparkToColumnar.supportedOperatorList` into Arrow columnar format before processing. | false |
+| `spark.comet.sparkToColumnar.supportedOperatorList` | A comma-separated list of operators that will be converted to Arrow columnar format when `spark.comet.sparkToColumnar.enabled` is true. | Range,InMemoryTableScan,RDDScan,OneRowRelation |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Viewing Explain Plan & Fallback Reasons
@@ -41,6 +85,17 @@ Comet provides the following configuration settings.
 These settings can be used to determine which parts of the plan are accelerated by Comet and to see why some parts of the plan could not be supported by Comet.
 
 <!--BEGIN:CONFIG_TABLE[exec_explain]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.explain.codegen.enabled` | When enabled, Comet annotates the surrounding Comet operator with a `[COMET-INFO: JVM codegen dispatcher: <names>]` segment listing every expression it routed through the JVM codegen dispatcher. Disabled by default. | false |
+| `spark.comet.explain.fallback.enabled` | When this setting is enabled, Comet will provide logging explaining the reason(s) why a query stage cannot be executed natively. Set this to false to reduce the amount of logging. | false |
+| `spark.comet.explain.fallback.log.enabled` | When this setting is enabled, Comet will log warnings for all fallback reasons. It can be overridden by the environment variable `ENABLE_COMET_LOG_FALLBACK_REASONS`. | false |
+| `spark.comet.explain.format` | Choose extended explain output. The default format of 'verbose' will provide the full query plan annotated with fallback reasons as well as a summary of how much of the plan was accelerated by Comet. The format 'fallback' provides a list of fallback reasons instead. | verbose |
+| `spark.comet.explain.native.enabled` | When this setting is enabled, Comet will provide a tree representation of the native query plan before execution and again after execution, with metrics. | false |
+| `spark.comet.explain.planOnly.enabled` | When enabled, Comet logs the plan it would have executed, with a coverage summary, to the driver log and then lets Spark execute the query unchanged. Native planning failures are not detected, so the coverage can be optimistic. Requires `spark.comet.exec.enabled=true`. | false |
+| `spark.comet.explain.rules` | When this setting is enabled, Comet will log all plan transformations performed in physical optimizer rules. Default: false | false |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Shuffle Configuration Settings
@@ -65,11 +120,47 @@ With dynamic allocation enabled, native Celeborn shuffle also requires either
 shuffle, including applications that rely only on remote reliable storage or decommissioning.
 
 <!--BEGIN:CONFIG_TABLE[shuffle]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.shuffle.compression.codec` | The codec of Comet native shuffle used to compress shuffle data. lz4, zstd, and snappy are supported. Compression can be disabled by setting spark.shuffle.compress=false. | lz4 |
+| `spark.comet.shuffle.compression.zstd.level` | The compression level to use when compressing shuffle files with zstd. | 1 |
+| `spark.comet.shuffle.convertFromSparkPlan.enabled` | When enabled, Comet will convert a Spark `ShuffleExchangeExec` to a Comet columnar shuffle even when its child is a non-Comet (Spark) plan. Disable to leave such shuffles as native Spark shuffles, restricting Comet shuffle to cases where the child is already a Comet plan. | true |
+| `spark.comet.shuffle.directRead.enabled` | When enabled, native operators that consume shuffle output will read compressed shuffle blocks directly in native code, bypassing Arrow FFI. Applies to both native shuffle and JVM columnar shuffle. Requires spark.comet.shuffle.enabled to be true. | true |
+| `spark.comet.shuffle.enabled` | Whether to enable Comet shuffle. Note that this requires setting `spark.shuffle.manager` to `org.apache.spark.sql.comet.execution.shuffle.CometShuffleManager` or `org.apache.spark.sql.comet.execution.shuffle.CometCelebornShuffleManager`. Celeborn requires explicit native mode and compatible application settings. `spark.shuffle.manager` must be set before starting the Spark application and cannot be changed during the application. | true |
+| `spark.comet.shuffle.jvm.batchSize` | Batch size when writing out sorted spill files on the native side. Note that this should not be larger than batch size (i.e., `spark.comet.batchSize`). Otherwise it will produce larger batches than expected in the native operator after shuffle. | 8192 |
+| `spark.comet.shuffle.jvm.maxWritersPerExecutor` | Maximum number of concurrent hash-based shuffle writers per executor. Comet's hash-based (bypass merge sort) columnar shuffle allocates one writer per partition, so `executor cores * numPartitions` writers can be active concurrently. When that product exceeds this cap, Comet falls back to sort-based shuffle to avoid OOM. | 100 |
+| `spark.comet.shuffle.jvm.preferDictionary.ratio` | The ratio of total values to distinct values in a string or binary column to decide whether to prefer dictionary encoding when shuffling the column. If the ratio is higher than this config, dictionary encoding will be used when shuffling the column. This config is effective if it is higher than 1.0. Note that this config is only used when `spark.comet.shuffle.mode` is `jvm`. | 10.0 |
+| `spark.comet.shuffle.mode` | Select the Comet shuffle implementation: `jvm` for Columnar Shuffle, `native` for Native Shuffle, and `auto` to pick the best supported option (`native` has priority). With CometCelebornShuffleManager, only explicit `native` mode enables Comet shuffle; `auto` and `jvm` retain Spark/Celeborn shuffle. For more information, refer to the [Comet Tuning Guide](https://datafusion.apache.org/comet/user-guide/latest/tuning.html). | auto |
+| `spark.comet.shuffle.native.maxBufferBytes` | Maximum number of bytes that the native shuffle writer will buffer in memory before spilling to disk. The default of 0 disables this limit, in which case spilling is triggered only when the memory pool denies an allocation. Setting a limit caps the writer's memory footprint independently of the size of the memory pool, at the cost of more frequent spilling. | 0b |
+| `spark.comet.shuffle.native.partitioning.hash.enabled` | Whether to enable hash partitioning for Comet native shuffle. | true |
+| `spark.comet.shuffle.native.partitioning.hash.nested.enabled` | Whether to allow nested types (struct, array, map) as hash partitioning keys in Comet native shuffle. Comet's native Murmur3 kernel hashes nested types recursively and shares that kernel, and Spark's seed, with the `hash` expression, so partition assignment matches Spark. A map key additionally requires the `mapsort` normalization that Spark 4.0 and later insert, so maps are rejected on earlier versions. Disabled by defaul [...]
+| `spark.comet.shuffle.native.partitioning.range.enabled` | Whether to enable range partitioning for Comet native shuffle. | true |
+| `spark.comet.shuffle.native.partitioning.roundrobin.enabled` | Whether to enable round robin partitioning for Comet native shuffle. This is disabled by default because Comet's round-robin produces different partition assignments than Spark. Spark sorts rows by their binary UnsafeRow representation before assigning partitions, but Comet uses Arrow format which has a different binary layout. Instead, Comet implements round-robin as hash partitioning on all columns, which achieves the sam [...]
+| `spark.comet.shuffle.native.partitioning.roundrobin.maxHashColumns` | The maximum number of columns to hash for round robin partitioning. When set to 0 (the default), all columns are hashed. When set to a positive value, only the first N columns are used for hashing, which can improve performance for wide tables while still providing reasonable distribution. | 0 |
+| `spark.comet.shuffle.native.partitioning.roundrobin.positional.enabled` | When true, Comet's native round-robin shuffle places rows by position rather than by hashing their contents, sending each map task's rows to the output partitions in turn, in contiguous groups. This skips a murmur3 pass over every column of every row and replaces the per-row gather on flush with a bulk copy per group, which is what dominates the shuffle write on wide nested schemas, and it spreads duplicate rows  [...]
+| `spark.comet.shuffle.native.partitioning.roundrobin.positional.groupRows` | Rows per contiguous group under positional round robin. Smaller groups balance better and larger ones are cheaper to copy. Within one map task, output partitions differ by at most this many rows, but a reducer receives groups from every map task, so the stage is only evenly balanced when each task emits many more groups than there are output partitions; a group approaching a task's whole input skews the stage a [...]
+| `spark.comet.shuffle.native.writeBufferSize` | Size of the write buffer in bytes used by the native shuffle writer when writing shuffle data to disk. Larger values may improve write performance by reducing the number of system calls, but will use more memory. The default is 1MB which provides a good balance between performance and memory usage. | 1048576b |
+| `spark.comet.shuffle.revertRedundantColumnar.enabled` | When enabled, Comet reverts a `CometShuffleExchangeExec` with `CometColumnarShuffle` back to Spark's `ShuffleExchangeExec` when both its parent and child are non-Comet hash aggregate operators. This avoids a redundant row -> Arrow -> shuffle -> Arrow -> row conversion when no Comet operator on either side can consume columnar output. Disable to keep Comet columnar shuffle even in that case, which preserves Comet's off-heap shuffle [...]
+| `spark.comet.shuffle.rss.maxFrameBytes` | Maximum encoded size of one complete native shuffle frame sent to a remote shuffle service. Frames are never split across remote push requests. | 67108864b |
+| `spark.comet.shuffle.rss.maxInFlightBytes` | Maximum shuffle bytes admitted concurrently by native Comet map attempts sharing an executor-side remote shuffle client. Admission includes native encoding scratch and overlapping native, JNI, and remote shuffle frame copies. A frame must fit its codec and Arrow workspace as well as its encoded bytes; ordinary uncompressed frames need approximately seven times their size plus schema and transport overhead. Compressed frames also reserve work [...]
+| `spark.comet.shuffle.sizeInBytesMultiplier` | Comet reports smaller sizes for shuffle due to using Arrow's columnar memory format and this can result in Spark choosing a different join strategy due to the estimated size of the exchange being smaller. Comet will multiple sizeInBytes by this amount to avoid regressions in join strategy. | 1.0 |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Memory & Tuning Configuration Settings
 
 <!--BEGIN:CONFIG_TABLE[tuning]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.batchSize` | The columnar batch size, i.e., the maximum number of rows that a batch can contain. | 8192 |
+| `spark.comet.exec.memoryPool` | The type of memory pool to be used for Comet native execution when running Spark in off-heap mode. Available pool types are `greedy_unified` and `fair_unified`. For more information, refer to the [Comet Tuning Guide](https://datafusion.apache.org/comet/user-guide/latest/tuning.html). | fair_unified |
+| `spark.comet.exec.memoryPool.fraction` | Deprecated: this config will be removed in a future major release. It does not leave room in spark.memory.offHeap.size for native memory that Comet's memory pools do not track, because Spark hands out the whole off-heap pool whatever this is set to. Size spark.executor.memoryOverhead for that memory instead. Only applies to off-heap mode, where the fair_unified pool limits each memory consumer in a task to this fraction of the off-heap size divi [...]
+| `spark.comet.maxTempDirectorySize` | The maximum amount of data (in bytes) stored inside the temporary directories used by native operators when spilling. Applied to each Comet native plan separately, and a Spark task can run more than one native plan at a time, so an executor running N concurrent tasks may use more than N times this value on shared local disks. Once the limit is reached, further spills will fail and the query will error out. | 107374182400b |
+| `spark.comet.memory.logInterval` | How often each executor logs its native memory usage at INFO level while Comet native plans are running: the bytes the native allocator has handed out, and the bytes reserved in Comet's memory pools. The difference is native memory that the pools are not accounting for. The executor logs one line per interval however many tasks are running, and one more after the last plan finishes. It logs a warning when the native memory looks larger than the execut [...]
+| `spark.comet.tracing.enabled` | Enable fine-grained tracing of events and memory usage. For more information, refer to the [Comet Tracing Guide](https://datafusion.apache.org/comet/contributor-guide/tracing.html). | false |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Development & Testing Settings
@@ -88,19 +179,374 @@ this page does not by itself mean that, though: the per-expression
 them like any other production setting.
 
 <!--BEGIN:CONFIG_TABLE[testing]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.debug.memory` | When enabled, log all native memory pool interactions. For more information, refer to the Comet Debugging Guide (https://datafusion.apache.org/comet/contributor-guide/debugging.html). | false |
+| `spark.comet.exec.onHeap.enabled` | Whether to allow Comet to run in on-heap mode. Required for running Spark SQL tests. Comet performs no memory accounting in on-heap mode, so its allocations are bounded by nothing; this must not be used in production. It can be overridden by the environment variable `ENABLE_COMET_ONHEAP`. | false |
+| `spark.comet.exec.respectDataFusionConfigs` | Development and testing configuration option to allow DataFusion configs set in Spark configuration settings starting with `spark.comet.datafusion.` to be passed into native execution. | false |
+| `spark.comet.iceberg.write.enabled` | Whether to delegate the executor-side Parquet write to Comet's native (iceberg-rust) writer when the table's properties allow it. Requires `spark.comet.write.iceberg.splitOperator.enabled = true`. Off by default. | false |
+| `spark.comet.parquet.write.enabled` | Whether to enable native Parquet write through Comet. When enabled, Comet will intercept Parquet write operations and execute them natively. This feature is highly experimental and only partially implemented. It should not be used in production. It can be overridden by the environment variable `ENABLE_COMET_WRITE`. | false |
+| `spark.comet.scan.csv.v2.enabled` | Whether to use the native Comet V2 CSV reader for improved performance. Default: false (uses standard Spark CSV reader) Experimental: Performance benefits are workload-dependent. | false |
+| `spark.comet.scan.enabled` | Whether to enable native scans. Intended for use in Comet's own test suites to selectively disable native scans; not intended for production use. | true |
+| `spark.comet.testing.strict` | Experimental option to enable strict testing, which will fail tests that could be more comprehensive, such as checking for a specific fallback reason. It can be overridden by the environment variable `ENABLE_COMET_STRICT_TESTING`. | false |
+| `spark.comet.write.iceberg.splitOperator.enabled` | Whether to rewrite Iceberg V2 writes from Spark's combined V2 write/commit operator into Comet's two-operator shape: a file writer exec (inside AQE) and a committer (outside AQE). | false |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Enabling or Disabling Individual Operators
 
 <!--BEGIN:CONFIG_TABLE[enable_exec]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.exec.aggregate.enabled` | Whether to enable aggregate by default. | true |
+| `spark.comet.exec.broadcastExchange.enabled` | Whether to enable broadcastExchange by default. | true |
+| `spark.comet.exec.broadcastHashJoin.enabled` | Whether to enable broadcastHashJoin by default. | true |
+| `spark.comet.exec.broadcastNestedLoopJoin.enabled` | Whether to enable broadcastNestedLoopJoin by default. | true |
+| `spark.comet.exec.coalesce.enabled` | Whether to enable coalesce by default. | true |
+| `spark.comet.exec.collectLimit.enabled` | Whether to enable collectLimit by default. | true |
+| `spark.comet.exec.emptyRelation.enabled` | Whether to enable emptyRelation by default. | true |
+| `spark.comet.exec.expand.enabled` | Whether to enable expand by default. | true |
+| `spark.comet.exec.explode.enabled` | Whether to enable explode by default. | true |
+| `spark.comet.exec.filter.enabled` | Whether to enable filter by default. | true |
+| `spark.comet.exec.globalLimit.enabled` | Whether to enable globalLimit by default. | true |
+| `spark.comet.exec.hashJoin.enabled` | Whether to enable hashJoin by default. | true |
+| `spark.comet.exec.localLimit.enabled` | Whether to enable localLimit by default. | true |
+| `spark.comet.exec.localTableScan.enabled` | Whether to enable localTableScan by default. | false |
+| `spark.comet.exec.project.enabled` | Whether to enable project by default. | true |
+| `spark.comet.exec.sample.enabled` | Whether to enable sample by default. | true |
+| `spark.comet.exec.sort.enabled` | Whether to enable sort by default. | true |
+| `spark.comet.exec.sortMergeJoin.enabled` | Whether to enable sortMergeJoin by default. | true |
+| `spark.comet.exec.sortMergeJoinWithJoinFilter.enabled` | Support for Sort Merge Join with filter. Deprecated: this config will be removed in a future major release. | true |
+| `spark.comet.exec.takeOrderedAndProject.enabled` | Whether to enable takeOrderedAndProject by default. | true |
+| `spark.comet.exec.union.enabled` | Whether to enable union by default. | true |
+| `spark.comet.exec.window.enabled` | Whether to enable window by default. | true |
+| `spark.comet.exec.windowGroupLimit.enabled` | Whether to enable windowGroupLimit by default. | true |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Enabling or Disabling Individual Scalar Expressions
 
 <!--BEGIN:CONFIG_TABLE[enable_expr]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.expression.Abs.enabled` | Enable Comet acceleration for `Abs` | true |
+| `spark.comet.expression.Acos.enabled` | Enable Comet acceleration for `Acos` | true |
+| `spark.comet.expression.Acosh.enabled` | Enable Comet acceleration for `Acosh` | true |
+| `spark.comet.expression.Add.enabled` | Enable Comet acceleration for `Add` | true |
+| `spark.comet.expression.AddMonths.enabled` | Enable Comet acceleration for `AddMonths` | true |
+| `spark.comet.expression.Alias.enabled` | Enable Comet acceleration for `Alias` | true |
+| `spark.comet.expression.And.enabled` | Enable Comet acceleration for `And` | true |
+| `spark.comet.expression.ApplyFunctionExpression.enabled` | Enable Comet acceleration for `ApplyFunctionExpression` | true |
+| `spark.comet.expression.ArrayAggregate.enabled` | Enable Comet acceleration for `ArrayAggregate` | true |
+| `spark.comet.expression.ArrayAppend.enabled` | Enable Comet acceleration for `ArrayAppend` | true |
+| `spark.comet.expression.ArrayContains.enabled` | Enable Comet acceleration for `ArrayContains` | true |
+| `spark.comet.expression.ArrayDistinct.enabled` | Enable Comet acceleration for `ArrayDistinct` | true |
+| `spark.comet.expression.ArrayExcept.enabled` | Enable Comet acceleration for `ArrayExcept` | true |
+| `spark.comet.expression.ArrayExists.enabled` | Enable Comet acceleration for `ArrayExists` | true |
+| `spark.comet.expression.ArrayFilter.enabled` | Enable Comet acceleration for `ArrayFilter` | true |
+| `spark.comet.expression.ArrayForAll.enabled` | Enable Comet acceleration for `ArrayForAll` | true |
+| `spark.comet.expression.ArrayInsert.enabled` | Enable Comet acceleration for `ArrayInsert` | true |
+| `spark.comet.expression.ArrayIntersect.enabled` | Enable Comet acceleration for `ArrayIntersect` | true |
+| `spark.comet.expression.ArrayJoin.enabled` | Enable Comet acceleration for `ArrayJoin` | true |
+| `spark.comet.expression.ArrayMax.enabled` | Enable Comet acceleration for `ArrayMax` | true |
+| `spark.comet.expression.ArrayMin.enabled` | Enable Comet acceleration for `ArrayMin` | true |
+| `spark.comet.expression.ArrayPosition.enabled` | Enable Comet acceleration for `ArrayPosition` | true |
+| `spark.comet.expression.ArrayRemove.enabled` | Enable Comet acceleration for `ArrayRemove` | true |
+| `spark.comet.expression.ArrayRepeat.enabled` | Enable Comet acceleration for `ArrayRepeat` | true |
+| `spark.comet.expression.ArraySort.enabled` | Enable Comet acceleration for `ArraySort` | true |
+| `spark.comet.expression.ArrayTransform.enabled` | Enable Comet acceleration for `ArrayTransform` | true |
+| `spark.comet.expression.ArrayUnion.enabled` | Enable Comet acceleration for `ArrayUnion` | true |
+| `spark.comet.expression.ArraysOverlap.enabled` | Enable Comet acceleration for `ArraysOverlap` | true |
+| `spark.comet.expression.ArraysZip.enabled` | Enable Comet acceleration for `ArraysZip` | true |
+| `spark.comet.expression.Ascii.enabled` | Enable Comet acceleration for `Ascii` | true |
+| `spark.comet.expression.Asin.enabled` | Enable Comet acceleration for `Asin` | true |
+| `spark.comet.expression.Asinh.enabled` | Enable Comet acceleration for `Asinh` | true |
+| `spark.comet.expression.Atan.enabled` | Enable Comet acceleration for `Atan` | true |
+| `spark.comet.expression.Atan2.enabled` | Enable Comet acceleration for `Atan2` | true |
+| `spark.comet.expression.Atanh.enabled` | Enable Comet acceleration for `Atanh` | true |
+| `spark.comet.expression.AttributeReference.enabled` | Enable Comet acceleration for `AttributeReference` | true |
+| `spark.comet.expression.BRound.enabled` | Enable Comet acceleration for `BRound` | true |
+| `spark.comet.expression.Base64.enabled` | Enable Comet acceleration for `Base64` | true |
+| `spark.comet.expression.Bin.enabled` | Enable Comet acceleration for `Bin` | true |
+| `spark.comet.expression.BitLength.enabled` | Enable Comet acceleration for `BitLength` | true |
+| `spark.comet.expression.BitwiseAnd.enabled` | Enable Comet acceleration for `BitwiseAnd` | true |
+| `spark.comet.expression.BitwiseCount.enabled` | Enable Comet acceleration for `BitwiseCount` | true |
+| `spark.comet.expression.BitwiseGet.enabled` | Enable Comet acceleration for `BitwiseGet` | true |
+| `spark.comet.expression.BitwiseNot.enabled` | Enable Comet acceleration for `BitwiseNot` | true |
+| `spark.comet.expression.BitwiseOr.enabled` | Enable Comet acceleration for `BitwiseOr` | true |
+| `spark.comet.expression.BitwiseXor.enabled` | Enable Comet acceleration for `BitwiseXor` | true |
+| `spark.comet.expression.BloomFilterMightContain.enabled` | Enable Comet acceleration for `BloomFilterMightContain` | true |
+| `spark.comet.expression.CaseWhen.enabled` | Enable Comet acceleration for `CaseWhen` | true |
+| `spark.comet.expression.Cast.enabled` | Enable Comet acceleration for `Cast` | true |
+| `spark.comet.expression.Cbrt.enabled` | Enable Comet acceleration for `Cbrt` | true |
+| `spark.comet.expression.Ceil.enabled` | Enable Comet acceleration for `Ceil` | true |
+| `spark.comet.expression.CheckOverflow.enabled` | Enable Comet acceleration for `CheckOverflow` | true |
+| `spark.comet.expression.Chr.enabled` | Enable Comet acceleration for `Chr` | true |
+| `spark.comet.expression.Coalesce.enabled` | Enable Comet acceleration for `Coalesce` | true |
+| `spark.comet.expression.Concat.enabled` | Enable Comet acceleration for `Concat` | true |
+| `spark.comet.expression.ConcatWs.enabled` | Enable Comet acceleration for `ConcatWs` | true |
+| `spark.comet.expression.Contains.enabled` | Enable Comet acceleration for `Contains` | true |
+| `spark.comet.expression.Conv.enabled` | Enable Comet acceleration for `Conv` | true |
+| `spark.comet.expression.ConvertTimezone.enabled` | Enable Comet acceleration for `ConvertTimezone` | true |
+| `spark.comet.expression.Cos.enabled` | Enable Comet acceleration for `Cos` | true |
+| `spark.comet.expression.Cosh.enabled` | Enable Comet acceleration for `Cosh` | true |
+| `spark.comet.expression.Cot.enabled` | Enable Comet acceleration for `Cot` | true |
+| `spark.comet.expression.Crc32.enabled` | Enable Comet acceleration for `Crc32` | true |
+| `spark.comet.expression.CreateArray.enabled` | Enable Comet acceleration for `CreateArray` | true |
+| `spark.comet.expression.CreateMap.enabled` | Enable Comet acceleration for `CreateMap` | true |
+| `spark.comet.expression.CreateNamedStruct.enabled` | Enable Comet acceleration for `CreateNamedStruct` | true |
+| `spark.comet.expression.Csc.enabled` | Enable Comet acceleration for `Csc` | true |
+| `spark.comet.expression.CsvToStructs.enabled` | Enable Comet acceleration for `CsvToStructs` | true |
+| `spark.comet.expression.DateAdd.enabled` | Enable Comet acceleration for `DateAdd` | true |
+| `spark.comet.expression.DateDiff.enabled` | Enable Comet acceleration for `DateDiff` | true |
+| `spark.comet.expression.DateFormatClass.enabled` | Enable Comet acceleration for `DateFormatClass` | true |
+| `spark.comet.expression.DateFromUnixDate.enabled` | Enable Comet acceleration for `DateFromUnixDate` | true |
+| `spark.comet.expression.DateSub.enabled` | Enable Comet acceleration for `DateSub` | true |
+| `spark.comet.expression.DayOfMonth.enabled` | Enable Comet acceleration for `DayOfMonth` | true |
+| `spark.comet.expression.DayOfWeek.enabled` | Enable Comet acceleration for `DayOfWeek` | true |
+| `spark.comet.expression.DayOfYear.enabled` | Enable Comet acceleration for `DayOfYear` | true |
+| `spark.comet.expression.Days.enabled` | Enable Comet acceleration for `Days` | true |
+| `spark.comet.expression.Divide.enabled` | Enable Comet acceleration for `Divide` | true |
+| `spark.comet.expression.ElementAt.enabled` | Enable Comet acceleration for `ElementAt` | true |
+| `spark.comet.expression.Elt.enabled` | Enable Comet acceleration for `Elt` | true |
+| `spark.comet.expression.Empty2Null.enabled` | Enable Comet acceleration for `Empty2Null` | true |
+| `spark.comet.expression.EndsWith.enabled` | Enable Comet acceleration for `EndsWith` | true |
+| `spark.comet.expression.EqualNullSafe.enabled` | Enable Comet acceleration for `EqualNullSafe` | true |
+| `spark.comet.expression.EqualTo.enabled` | Enable Comet acceleration for `EqualTo` | true |
+| `spark.comet.expression.Exp.enabled` | Enable Comet acceleration for `Exp` | true |
+| `spark.comet.expression.Expm1.enabled` | Enable Comet acceleration for `Expm1` | true |
+| `spark.comet.expression.Factorial.enabled` | Enable Comet acceleration for `Factorial` | true |
+| `spark.comet.expression.FindInSet.enabled` | Enable Comet acceleration for `FindInSet` | true |
+| `spark.comet.expression.Flatten.enabled` | Enable Comet acceleration for `Flatten` | true |
+| `spark.comet.expression.Floor.enabled` | Enable Comet acceleration for `Floor` | true |
+| `spark.comet.expression.FormatNumber.enabled` | Enable Comet acceleration for `FormatNumber` | true |
+| `spark.comet.expression.FormatString.enabled` | Enable Comet acceleration for `FormatString` | true |
+| `spark.comet.expression.FromUTCTimestamp.enabled` | Enable Comet acceleration for `FromUTCTimestamp` | true |
+| `spark.comet.expression.FromUnixTime.enabled` | Enable Comet acceleration for `FromUnixTime` | true |
+| `spark.comet.expression.GetArrayItem.enabled` | Enable Comet acceleration for `GetArrayItem` | true |
+| `spark.comet.expression.GetArrayStructFields.enabled` | Enable Comet acceleration for `GetArrayStructFields` | true |
+| `spark.comet.expression.GetJsonObject.enabled` | Enable Comet acceleration for `GetJsonObject` | true |
+| `spark.comet.expression.GetMapValue.enabled` | Enable Comet acceleration for `GetMapValue` | true |
+| `spark.comet.expression.GetStructField.enabled` | Enable Comet acceleration for `GetStructField` | true |
+| `spark.comet.expression.GetTimestamp.enabled` | Enable Comet acceleration for `GetTimestamp` | true |
+| `spark.comet.expression.GreaterThan.enabled` | Enable Comet acceleration for `GreaterThan` | true |
+| `spark.comet.expression.GreaterThanOrEqual.enabled` | Enable Comet acceleration for `GreaterThanOrEqual` | true |
+| `spark.comet.expression.Greatest.enabled` | Enable Comet acceleration for `Greatest` | true |
+| `spark.comet.expression.Hex.enabled` | Enable Comet acceleration for `Hex` | true |
+| `spark.comet.expression.Hour.enabled` | Enable Comet acceleration for `Hour` | true |
+| `spark.comet.expression.Hours.enabled` | Enable Comet acceleration for `Hours` | true |
+| `spark.comet.expression.Hypot.enabled` | Enable Comet acceleration for `Hypot` | true |
+| `spark.comet.expression.If.enabled` | Enable Comet acceleration for `If` | true |
+| `spark.comet.expression.In.enabled` | Enable Comet acceleration for `In` | true |
+| `spark.comet.expression.InSet.enabled` | Enable Comet acceleration for `InSet` | true |
+| `spark.comet.expression.InitCap.enabled` | Enable Comet acceleration for `InitCap` | true |
+| `spark.comet.expression.IntegralDivide.enabled` | Enable Comet acceleration for `IntegralDivide` | true |
+| `spark.comet.expression.Invoke.enabled` | Enable Comet acceleration for `Invoke` | true |
+| `spark.comet.expression.IsNaN.enabled` | Enable Comet acceleration for `IsNaN` | true |
+| `spark.comet.expression.IsNotNull.enabled` | Enable Comet acceleration for `IsNotNull` | true |
+| `spark.comet.expression.IsNull.enabled` | Enable Comet acceleration for `IsNull` | true |
+| `spark.comet.expression.JsonObjectKeys.enabled` | Enable Comet acceleration for `JsonObjectKeys` | true |
+| `spark.comet.expression.JsonToStructs.enabled` | Enable Comet acceleration for `JsonToStructs` | true |
+| `spark.comet.expression.KnownFloatingPointNormalized.enabled` | Enable Comet acceleration for `KnownFloatingPointNormalized` | true |
+| `spark.comet.expression.KnownNotNull.enabled` | Enable Comet acceleration for `KnownNotNull` | true |
+| `spark.comet.expression.KnownNullable.enabled` | Enable Comet acceleration for `KnownNullable` | true |
+| `spark.comet.expression.LastDay.enabled` | Enable Comet acceleration for `LastDay` | true |
+| `spark.comet.expression.Least.enabled` | Enable Comet acceleration for `Least` | true |
+| `spark.comet.expression.Left.enabled` | Enable Comet acceleration for `Left` | true |
+| `spark.comet.expression.Length.enabled` | Enable Comet acceleration for `Length` | true |
+| `spark.comet.expression.LengthOfJsonArray.enabled` | Enable Comet acceleration for `LengthOfJsonArray` | true |
+| `spark.comet.expression.LessThan.enabled` | Enable Comet acceleration for `LessThan` | true |
+| `spark.comet.expression.LessThanOrEqual.enabled` | Enable Comet acceleration for `LessThanOrEqual` | true |
+| `spark.comet.expression.Levenshtein.enabled` | Enable Comet acceleration for `Levenshtein` | true |
+| `spark.comet.expression.Like.enabled` | Enable Comet acceleration for `Like` | true |
+| `spark.comet.expression.Literal.enabled` | Enable Comet acceleration for `Literal` | true |
+| `spark.comet.expression.Log.enabled` | Enable Comet acceleration for `Log` | true |
+| `spark.comet.expression.Log10.enabled` | Enable Comet acceleration for `Log10` | true |
+| `spark.comet.expression.Log1p.enabled` | Enable Comet acceleration for `Log1p` | true |
+| `spark.comet.expression.Log2.enabled` | Enable Comet acceleration for `Log2` | true |
+| `spark.comet.expression.Logarithm.enabled` | Enable Comet acceleration for `Logarithm` | true |
+| `spark.comet.expression.Lower.enabled` | Enable Comet acceleration for `Lower` | true |
+| `spark.comet.expression.MakeDTInterval.enabled` | Enable Comet acceleration for `MakeDTInterval` | true |
+| `spark.comet.expression.MakeDate.enabled` | Enable Comet acceleration for `MakeDate` | true |
+| `spark.comet.expression.MakeDecimal.enabled` | Enable Comet acceleration for `MakeDecimal` | true |
+| `spark.comet.expression.MakeInterval.enabled` | Enable Comet acceleration for `MakeInterval` | true |
+| `spark.comet.expression.MakeTimestamp.enabled` | Enable Comet acceleration for `MakeTimestamp` | true |
+| `spark.comet.expression.MakeYMInterval.enabled` | Enable Comet acceleration for `MakeYMInterval` | true |
+| `spark.comet.expression.MapConcat.enabled` | Enable Comet acceleration for `MapConcat` | true |
+| `spark.comet.expression.MapEntries.enabled` | Enable Comet acceleration for `MapEntries` | true |
+| `spark.comet.expression.MapFilter.enabled` | Enable Comet acceleration for `MapFilter` | true |
+| `spark.comet.expression.MapFromArrays.enabled` | Enable Comet acceleration for `MapFromArrays` | true |
+| `spark.comet.expression.MapFromEntries.enabled` | Enable Comet acceleration for `MapFromEntries` | true |
+| `spark.comet.expression.MapKeys.enabled` | Enable Comet acceleration for `MapKeys` | true |
+| `spark.comet.expression.MapSort.enabled` | Enable Comet acceleration for `MapSort` | true |
+| `spark.comet.expression.MapValues.enabled` | Enable Comet acceleration for `MapValues` | true |
+| `spark.comet.expression.MapZipWith.enabled` | Enable Comet acceleration for `MapZipWith` | true |
+| `spark.comet.expression.Mask.enabled` | Enable Comet acceleration for `Mask` | true |
+| `spark.comet.expression.Md5.enabled` | Enable Comet acceleration for `Md5` | true |
+| `spark.comet.expression.MicrosToTimestamp.enabled` | Enable Comet acceleration for `MicrosToTimestamp` | true |
+| `spark.comet.expression.MillisToTimestamp.enabled` | Enable Comet acceleration for `MillisToTimestamp` | true |
+| `spark.comet.expression.Minute.enabled` | Enable Comet acceleration for `Minute` | true |
+| `spark.comet.expression.MonotonicallyIncreasingID.enabled` | Enable Comet acceleration for `MonotonicallyIncreasingID` | true |
+| `spark.comet.expression.Month.enabled` | Enable Comet acceleration for `Month` | true |
+| `spark.comet.expression.MonthsBetween.enabled` | Enable Comet acceleration for `MonthsBetween` | true |
+| `spark.comet.expression.Multiply.enabled` | Enable Comet acceleration for `Multiply` | true |
+| `spark.comet.expression.MultiplyDTInterval.enabled` | Enable Comet acceleration for `MultiplyDTInterval` | true |
+| `spark.comet.expression.Murmur3Hash.enabled` | Enable Comet acceleration for `Murmur3Hash` | true |
+| `spark.comet.expression.NaNvl.enabled` | Enable Comet acceleration for `NaNvl` | true |
+| `spark.comet.expression.NextDay.enabled` | Enable Comet acceleration for `NextDay` | true |
+| `spark.comet.expression.Not.enabled` | Enable Comet acceleration for `Not` | true |
+| `spark.comet.expression.OctetLength.enabled` | Enable Comet acceleration for `OctetLength` | true |
+| `spark.comet.expression.Or.enabled` | Enable Comet acceleration for `Or` | true |
+| `spark.comet.expression.Overlay.enabled` | Enable Comet acceleration for `Overlay` | true |
+| `spark.comet.expression.ParseUrl.enabled` | Enable Comet acceleration for `ParseUrl` | true |
+| `spark.comet.expression.Pi.enabled` | Enable Comet acceleration for `Pi` | true |
+| `spark.comet.expression.Pmod.enabled` | Enable Comet acceleration for `Pmod` | true |
+| `spark.comet.expression.Pow.enabled` | Enable Comet acceleration for `Pow` | true |
+| `spark.comet.expression.PreciseTimestampConversion.enabled` | Enable Comet acceleration for `PreciseTimestampConversion` | true |
+| `spark.comet.expression.Quarter.enabled` | Enable Comet acceleration for `Quarter` | true |
+| `spark.comet.expression.RLike.enabled` | Enable Comet acceleration for `RLike` | true |
+| `spark.comet.expression.Rand.enabled` | Enable Comet acceleration for `Rand` | true |
+| `spark.comet.expression.RandStr.enabled` | Enable Comet acceleration for `RandStr` | true |
+| `spark.comet.expression.Randn.enabled` | Enable Comet acceleration for `Randn` | true |
+| `spark.comet.expression.RegExpExtract.enabled` | Enable Comet acceleration for `RegExpExtract` | true |
+| `spark.comet.expression.RegExpExtractAll.enabled` | Enable Comet acceleration for `RegExpExtractAll` | true |
+| `spark.comet.expression.RegExpInStr.enabled` | Enable Comet acceleration for `RegExpInStr` | true |
+| `spark.comet.expression.RegExpReplace.enabled` | Enable Comet acceleration for `RegExpReplace` | true |
+| `spark.comet.expression.Remainder.enabled` | Enable Comet acceleration for `Remainder` | true |
+| `spark.comet.expression.Reverse.enabled` | Enable Comet acceleration for `Reverse` | true |
+| `spark.comet.expression.Right.enabled` | Enable Comet acceleration for `Right` | true |
+| `spark.comet.expression.Rint.enabled` | Enable Comet acceleration for `Rint` | true |
+| `spark.comet.expression.Round.enabled` | Enable Comet acceleration for `Round` | true |
+| `spark.comet.expression.ScalaUDF.enabled` | Enable Comet acceleration for `ScalaUDF` | true |
+| `spark.comet.expression.ScalarSubquery.enabled` | Enable Comet acceleration for `ScalarSubquery` | true |
+| `spark.comet.expression.SchemaOfCsv.enabled` | Enable Comet acceleration for `SchemaOfCsv` | true |
+| `spark.comet.expression.SchemaOfJson.enabled` | Enable Comet acceleration for `SchemaOfJson` | true |
+| `spark.comet.expression.Sec.enabled` | Enable Comet acceleration for `Sec` | true |
+| `spark.comet.expression.Second.enabled` | Enable Comet acceleration for `Second` | true |
+| `spark.comet.expression.SecondsToTimestamp.enabled` | Enable Comet acceleration for `SecondsToTimestamp` | true |
+| `spark.comet.expression.Sequence.enabled` | Enable Comet acceleration for `Sequence` | true |
+| `spark.comet.expression.Sha1.enabled` | Enable Comet acceleration for `Sha1` | true |
+| `spark.comet.expression.Sha2.enabled` | Enable Comet acceleration for `Sha2` | true |
+| `spark.comet.expression.ShiftLeft.enabled` | Enable Comet acceleration for `ShiftLeft` | true |
+| `spark.comet.expression.ShiftRight.enabled` | Enable Comet acceleration for `ShiftRight` | true |
+| `spark.comet.expression.ShiftRightUnsigned.enabled` | Enable Comet acceleration for `ShiftRightUnsigned` | true |
+| `spark.comet.expression.Shuffle.enabled` | Enable Comet acceleration for `Shuffle` | true |
+| `spark.comet.expression.Signum.enabled` | Enable Comet acceleration for `Signum` | true |
+| `spark.comet.expression.Sin.enabled` | Enable Comet acceleration for `Sin` | true |
+| `spark.comet.expression.Sinh.enabled` | Enable Comet acceleration for `Sinh` | true |
+| `spark.comet.expression.Size.enabled` | Enable Comet acceleration for `Size` | true |
+| `spark.comet.expression.Slice.enabled` | Enable Comet acceleration for `Slice` | true |
+| `spark.comet.expression.SortArray.enabled` | Enable Comet acceleration for `SortArray` | true |
+| `spark.comet.expression.SortOrder.enabled` | Enable Comet acceleration for `SortOrder` | true |
+| `spark.comet.expression.SoundEx.enabled` | Enable Comet acceleration for `SoundEx` | true |
+| `spark.comet.expression.SparkPartitionID.enabled` | Enable Comet acceleration for `SparkPartitionID` | true |
+| `spark.comet.expression.Sqrt.enabled` | Enable Comet acceleration for `Sqrt` | true |
+| `spark.comet.expression.StartsWith.enabled` | Enable Comet acceleration for `StartsWith` | true |
+| `spark.comet.expression.StaticInvoke.enabled` | Enable Comet acceleration for `StaticInvoke` | true |
+| `spark.comet.expression.StringInstr.enabled` | Enable Comet acceleration for `StringInstr` | true |
+| `spark.comet.expression.StringLPad.enabled` | Enable Comet acceleration for `StringLPad` | true |
+| `spark.comet.expression.StringLocate.enabled` | Enable Comet acceleration for `StringLocate` | true |
+| `spark.comet.expression.StringRPad.enabled` | Enable Comet acceleration for `StringRPad` | true |
+| `spark.comet.expression.StringRepeat.enabled` | Enable Comet acceleration for `StringRepeat` | true |
+| `spark.comet.expression.StringReplace.enabled` | Enable Comet acceleration for `StringReplace` | true |
+| `spark.comet.expression.StringSpace.enabled` | Enable Comet acceleration for `StringSpace` | true |
+| `spark.comet.expression.StringSplit.enabled` | Enable Comet acceleration for `StringSplit` | true |
+| `spark.comet.expression.StringToMap.enabled` | Enable Comet acceleration for `StringToMap` | true |
+| `spark.comet.expression.StringTranslate.enabled` | Enable Comet acceleration for `StringTranslate` | true |
+| `spark.comet.expression.StringTrim.enabled` | Enable Comet acceleration for `StringTrim` | true |
+| `spark.comet.expression.StringTrimLeft.enabled` | Enable Comet acceleration for `StringTrimLeft` | true |
+| `spark.comet.expression.StringTrimRight.enabled` | Enable Comet acceleration for `StringTrimRight` | true |
+| `spark.comet.expression.StructsToCsv.enabled` | Enable Comet acceleration for `StructsToCsv` | true |
+| `spark.comet.expression.StructsToJson.enabled` | Enable Comet acceleration for `StructsToJson` | true |
+| `spark.comet.expression.Substring.enabled` | Enable Comet acceleration for `Substring` | true |
+| `spark.comet.expression.SubstringIndex.enabled` | Enable Comet acceleration for `SubstringIndex` | true |
+| `spark.comet.expression.Subtract.enabled` | Enable Comet acceleration for `Subtract` | true |
+| `spark.comet.expression.Tan.enabled` | Enable Comet acceleration for `Tan` | true |
+| `spark.comet.expression.Tanh.enabled` | Enable Comet acceleration for `Tanh` | true |
+| `spark.comet.expression.TimestampAdd.enabled` | Enable Comet acceleration for `TimestampAdd` | true |
+| `spark.comet.expression.TimestampDiff.enabled` | Enable Comet acceleration for `TimestampDiff` | true |
+| `spark.comet.expression.ToCharacter.enabled` | Enable Comet acceleration for `ToCharacter` | true |
+| `spark.comet.expression.ToDegrees.enabled` | Enable Comet acceleration for `ToDegrees` | true |
+| `spark.comet.expression.ToNumber.enabled` | Enable Comet acceleration for `ToNumber` | true |
+| `spark.comet.expression.ToPrettyString.enabled` | Enable Comet acceleration for `ToPrettyString` | true |
+| `spark.comet.expression.ToRadians.enabled` | Enable Comet acceleration for `ToRadians` | true |
+| `spark.comet.expression.ToUTCTimestamp.enabled` | Enable Comet acceleration for `ToUTCTimestamp` | true |
+| `spark.comet.expression.ToUnixTimestamp.enabled` | Enable Comet acceleration for `ToUnixTimestamp` | true |
+| `spark.comet.expression.TransformKeys.enabled` | Enable Comet acceleration for `TransformKeys` | true |
+| `spark.comet.expression.TransformValues.enabled` | Enable Comet acceleration for `TransformValues` | true |
+| `spark.comet.expression.TruncDate.enabled` | Enable Comet acceleration for `TruncDate` | true |
+| `spark.comet.expression.TruncTimestamp.enabled` | Enable Comet acceleration for `TruncTimestamp` | true |
+| `spark.comet.expression.TryEval.enabled` | Enable Comet acceleration for `TryEval` | true |
+| `spark.comet.expression.TryToNumber.enabled` | Enable Comet acceleration for `TryToNumber` | true |
+| `spark.comet.expression.UnBase64.enabled` | Enable Comet acceleration for `UnBase64` | true |
+| `spark.comet.expression.UnaryMinus.enabled` | Enable Comet acceleration for `UnaryMinus` | true |
+| `spark.comet.expression.UnaryPositive.enabled` | Enable Comet acceleration for `UnaryPositive` | true |
+| `spark.comet.expression.Unhex.enabled` | Enable Comet acceleration for `Unhex` | true |
+| `spark.comet.expression.UnixDate.enabled` | Enable Comet acceleration for `UnixDate` | true |
+| `spark.comet.expression.UnixMicros.enabled` | Enable Comet acceleration for `UnixMicros` | true |
+| `spark.comet.expression.UnixMillis.enabled` | Enable Comet acceleration for `UnixMillis` | true |
+| `spark.comet.expression.UnixSeconds.enabled` | Enable Comet acceleration for `UnixSeconds` | true |
+| `spark.comet.expression.UnixTimestamp.enabled` | Enable Comet acceleration for `UnixTimestamp` | true |
+| `spark.comet.expression.UnscaledValue.enabled` | Enable Comet acceleration for `UnscaledValue` | true |
+| `spark.comet.expression.Upper.enabled` | Enable Comet acceleration for `Upper` | true |
+| `spark.comet.expression.Uuid.enabled` | Enable Comet acceleration for `Uuid` | true |
+| `spark.comet.expression.WeekDay.enabled` | Enable Comet acceleration for `WeekDay` | true |
+| `spark.comet.expression.WeekOfYear.enabled` | Enable Comet acceleration for `WeekOfYear` | true |
+| `spark.comet.expression.WidthBucket.enabled` | Enable Comet acceleration for `WidthBucket` | true |
+| `spark.comet.expression.XPathBoolean.enabled` | Enable Comet acceleration for `XPathBoolean` | true |
+| `spark.comet.expression.XPathDouble.enabled` | Enable Comet acceleration for `XPathDouble` | true |
+| `spark.comet.expression.XPathFloat.enabled` | Enable Comet acceleration for `XPathFloat` | true |
+| `spark.comet.expression.XPathInt.enabled` | Enable Comet acceleration for `XPathInt` | true |
+| `spark.comet.expression.XPathList.enabled` | Enable Comet acceleration for `XPathList` | true |
+| `spark.comet.expression.XPathLong.enabled` | Enable Comet acceleration for `XPathLong` | true |
+| `spark.comet.expression.XPathShort.enabled` | Enable Comet acceleration for `XPathShort` | true |
+| `spark.comet.expression.XPathString.enabled` | Enable Comet acceleration for `XPathString` | true |
+| `spark.comet.expression.XxHash64.enabled` | Enable Comet acceleration for `XxHash64` | true |
+| `spark.comet.expression.Year.enabled` | Enable Comet acceleration for `Year` | true |
+| `spark.comet.expression.ZipWith.enabled` | Enable Comet acceleration for `ZipWith` | true |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
 
 ## Enabling or Disabling Individual Aggregate Expressions
 
 <!--BEGIN:CONFIG_TABLE[enable_agg_expr]-->
+<!-- prettier-ignore-start -->
+| Config | Description | Default Value |
+|--------|-------------|---------------|
+| `spark.comet.expression.ApproximatePercentile.enabled` | Enable Comet acceleration for `ApproximatePercentile` | true |
+| `spark.comet.expression.Average.enabled` | Enable Comet acceleration for `Average` | true |
+| `spark.comet.expression.BitAndAgg.enabled` | Enable Comet acceleration for `BitAndAgg` | true |
+| `spark.comet.expression.BitOrAgg.enabled` | Enable Comet acceleration for `BitOrAgg` | true |
+| `spark.comet.expression.BitXorAgg.enabled` | Enable Comet acceleration for `BitXorAgg` | true |
+| `spark.comet.expression.BloomFilterAggregate.enabled` | Enable Comet acceleration for `BloomFilterAggregate` | true |
+| `spark.comet.expression.CollectList.enabled` | Enable Comet acceleration for `CollectList` | true |
+| `spark.comet.expression.CollectSet.enabled` | Enable Comet acceleration for `CollectSet` | true |
+| `spark.comet.expression.Corr.enabled` | Enable Comet acceleration for `Corr` | true |
+| `spark.comet.expression.Count.enabled` | Enable Comet acceleration for `Count` | true |
+| `spark.comet.expression.CovPopulation.enabled` | Enable Comet acceleration for `CovPopulation` | true |
+| `spark.comet.expression.CovSample.enabled` | Enable Comet acceleration for `CovSample` | true |
+| `spark.comet.expression.First.enabled` | Enable Comet acceleration for `First` | true |
+| `spark.comet.expression.HyperLogLogPlusPlus.enabled` | Enable Comet acceleration for `HyperLogLogPlusPlus` | true |
+| `spark.comet.expression.Last.enabled` | Enable Comet acceleration for `Last` | true |
+| `spark.comet.expression.ListAgg.enabled` | Enable Comet acceleration for `ListAgg` | true |
+| `spark.comet.expression.Max.enabled` | Enable Comet acceleration for `Max` | true |
+| `spark.comet.expression.MaxBy.enabled` | Enable Comet acceleration for `MaxBy` | true |
+| `spark.comet.expression.Min.enabled` | Enable Comet acceleration for `Min` | true |
+| `spark.comet.expression.MinBy.enabled` | Enable Comet acceleration for `MinBy` | true |
+| `spark.comet.expression.Mode.enabled` | Enable Comet acceleration for `Mode` | true |
+| `spark.comet.expression.Percentile.enabled` | Enable Comet acceleration for `Percentile` | true |
+| `spark.comet.expression.RegrIntercept.enabled` | Enable Comet acceleration for `RegrIntercept` | true |
+| `spark.comet.expression.RegrR2.enabled` | Enable Comet acceleration for `RegrR2` | true |
+| `spark.comet.expression.RegrReplacement.enabled` | Enable Comet acceleration for `RegrReplacement` | true |
+| `spark.comet.expression.RegrSXY.enabled` | Enable Comet acceleration for `RegrSXY` | true |
+| `spark.comet.expression.RegrSlope.enabled` | Enable Comet acceleration for `RegrSlope` | true |
+| `spark.comet.expression.StddevPop.enabled` | Enable Comet acceleration for `StddevPop` | true |
+| `spark.comet.expression.StddevSamp.enabled` | Enable Comet acceleration for `StddevSamp` | true |
+| `spark.comet.expression.Sum.enabled` | Enable Comet acceleration for `Sum` | true |
+| `spark.comet.expression.VariancePop.enabled` | Enable Comet acceleration for `VariancePop` | true |
+| `spark.comet.expression.VarianceSamp.enabled` | Enable Comet acceleration for `VarianceSamp` | true |
+<!-- prettier-ignore-end -->
 <!--END:CONFIG_TABLE-->
diff --git a/docs/source/user-guide/latest/expressions.md b/docs/source/user-guide/latest/expressions.md
index 1328f9029e..c60948d5df 100644
--- a/docs/source/user-guide/latest/expressions.md
+++ b/docs/source/user-guide/latest/expressions.md
@@ -114,7 +114,7 @@ The tables below list every Spark built-in expression with its current status.
 | `median` | ✅ | — | Rewrites to `percentile(col, 0.5)` and runs natively for supported percentile inputs |
 | `min` | ✅ | Native |  |
 | `min_by` | ✅ | Native | Value and ordering must be fixed-length types |
-| `mode` | ✅ | Native | `mode(col)` only; Spark breaks ties non-deterministically, so Comet returns the smallest tied value and falls back by default, opt-in via allowIncompatible |
+| `mode` | ✅ | — | `mode(col)` only; Spark breaks ties non-deterministically, so Comet returns the smallest tied value and falls back by default, opt-in via allowIncompatible |
 | `percentile` | ✅ | Native | Single literal percentage on numeric input runs natively; array of percentages and a frequency argument fall back to Spark |
 | `percentile_approx` | ✅ | Native | Alias of `approx_percentile`; same restrictions apply |
 | `percentile_cont` | ✅ | — | Spark 4.0+ `WITHIN GROUP (ORDER BY ...)`; ascending only runs natively, `DESC` falls back to Spark |
@@ -125,9 +125,9 @@ The tables below list every Spark built-in expression with its current status.
 | `regr_intercept` | ✅ | Native |  |
 | `regr_r2` | ✅ | Native |  |
 | `regr_slope` | ✅ | Native |  |
-| `regr_sxx` | ✅ | Native |  |
+| `regr_sxx` | ✅ | — |  |
 | `regr_sxy` | ✅ | Native |  |
-| `regr_syy` | ✅ | Native |  |
+| `regr_syy` | ✅ | — |  |
 | `skewness` | 🔜 | — | Not yet implemented natively |
 | `some` | ✅ | — |  |
 | `std` | ✅ | Native |  |
@@ -151,7 +151,7 @@ The tables below list every Spark built-in expression with its current status.
 | `array` | ✅ | Native |  |
 | `array_append` | ✅ | Native |  |
 | `array_compact` | ✅ | — |  |
-| `array_contains` | ✅ | Native | Float/double element arrays route through the JVM codegen dispatcher by default; the native path is opt-in via allowIncompatible |
+| `array_contains` | ✅ | Hybrid | Float/double element arrays route through the JVM codegen dispatcher by default; the native path is opt-in via allowIncompatible |
 | `array_distinct` | ✅ | Native | NaN/signed-zero handling may differ ([details](compatibility/floating-point.md)) |
 | `array_except` | ✅ | Hybrid | Routes through the JVM codegen dispatcher by default; the incompatible native path is opt-in via allowIncompatible ([details](compatibility/expressions/array.md)) |
 | `array_insert` | ✅ | Native |  |
@@ -181,9 +181,9 @@ The tables below list every Spark built-in expression with its current status.
 | Function | Status | Implementation | Notes |
 | --- | --- | --- | --- |
 | `&` | ✅ | Native |  |
-| `<<` | ✅ | — |  |
-| `>>` | ✅ | — |  |
-| `>>>` | ✅ | — | Operator alias for `shiftrightunsigned` (Spark 4.0+) |
+| `<<` | ✅ | Native |  |
+| `>>` | ✅ | Native |  |
+| `>>>` | ✅ | Native | Operator alias for `shiftrightunsigned` (Spark 4.0+) |
 | `^` | ✅ | Native |  |
 | `bit_count` | ✅ | Native |  |
 | `bit_get` | ✅ | Native |  |
@@ -230,7 +230,7 @@ The type-name conversion functions (`bigint`, `binary`, `boolean`, `date`, `deci
 
 | Function | Status | Implementation | Notes |
 | --- | --- | --- | --- |
-| `cast` | ✅ | Native | Casts without a native path (for example boolean to decimal) route through the JVM codegen dispatcher ([details](compatibility/expressions/cast.md)) |
+| `cast` | ✅ | Hybrid | Casts without a native path (for example boolean to decimal) route through the JVM codegen dispatcher ([details](compatibility/expressions/cast.md)) |
 
 ---
 
@@ -273,25 +273,25 @@ The type-name conversion functions (`bigint`, `binary`, `boolean`, `date`, `deci
 | `extract` | ✅ | — | `SECOND FROM TIME` is native for Spark 4.1+ with `Decimal(8,6)` output |
 | `from_unixtime` | ✅ | Hybrid |  |
 | `from_utc_timestamp` | ✅ | Hybrid | Routes through the JVM codegen dispatcher by default (handles all timezone forms); the native path is opt-in via allowIncompatible ([details](compatibility/expressions/datetime.md)) |
-| `hour` | ✅ | Native |  |
+| `hour` | ✅ | — |  |
 | `last_day` | ✅ | Native |  |
 | `localtimestamp` | ✅ | — |  |
 | `make_date` | ✅ | Native |  |
 | `make_dt_interval` | ✅ | Codegen dispatch |  |
 | `make_interval` | ✅ | Hybrid | Routes through the JVM codegen dispatcher by default; intervals outside Arrow's nanosecond range are tracked by [#5279](https://github.com/apache/datafusion-comet/issues/5279); the native path is opt-in via allowIncompatible ([details](compatibility/expressions/datetime.md)) |
 | `make_time` | ✅ | — | Spark 4.1+; requires `spark.sql.timeType.enabled=true`, which Spark leaves off by default. Runs natively; remaining TIME type work is tracked by [#4288](https://github.com/apache/datafusion-comet/issues/4288) |
-| `make_timestamp` | ✅ | Hybrid |  |
+| `make_timestamp` | ✅ | — |  |
 | `make_timestamp_ltz` | ✅ | — | 2-arg TIME form falls back |
 | `make_timestamp_ntz` | ✅ | — | 2-arg TIME form falls back |
 | `make_ym_interval` | ✅ | Codegen dispatch |  |
-| `minute` | ✅ | Native |  |
+| `minute` | ✅ | — |  |
 | `month` | ✅ | Native |  |
 | `monthname` | ✅ | — | Abbreviated month name (Spark 4.0+) |
 | `months_between` | ✅ | Codegen dispatch |  |
 | `next_day` | ✅ | Hybrid | Non-UTF8_BINARY collated `dayOfWeek` routes through the JVM codegen dispatcher; other input runs natively |
 | `now` | ✅ | — | Constant-folded to a literal (alias of `current_timestamp`) |
 | `quarter` | ✅ | Native |  |
-| `second` | ✅ | Native |  |
+| `second` | ✅ | — |  |
 | `session_window` | 🔜 | — | Batch session-window grouping falls back (`UpdatingSessionsExec` is not yet native); tracked by [#4785](https://github.com/apache/datafusion-comet/issues/4785) |
 | `time_diff` | 🔜 | — | Spark 4.1 TIME type; tracked by [#4288](https://github.com/apache/datafusion-comet/issues/4288) |
 | `time_trunc` | 🔜 | — | Spark 4.1 TIME type; tracked by [#4288](https://github.com/apache/datafusion-comet/issues/4288) |
@@ -306,7 +306,7 @@ The type-name conversion functions (`bigint`, `binary`, `boolean`, `date`, `deci
 | `to_timestamp` | ✅ | — | Rewrites to `Cast` (or `GetTimestamp` with a format) before Comet sees the plan |
 | `to_timestamp_ltz` | ✅ | — | Rewrites to `to_timestamp` (`TimestampType`) |
 | `to_timestamp_ntz` | ✅ | — | Rewrites to `to_timestamp` (`TimestampNTZType`) |
-| `to_unix_timestamp` | ✅ | Hybrid |  |
+| `to_unix_timestamp` | ✅ | Codegen dispatch |  |
 | `to_utc_timestamp` | ✅ | Hybrid | Routes through the JVM codegen dispatcher by default (handles all timezone forms); the native path is opt-in via allowIncompatible ([details](compatibility/expressions/datetime.md)) |
 | `trunc` | ✅ | Hybrid |  |
 | `try_make_interval` | ✅ | — | Rewrites to `MakeInterval`; same support as `make_interval` (Spark 4.0+) |
@@ -611,15 +611,15 @@ to Spark ([#2837](https://github.com/apache/datafusion-comet/issues/2837)). Enab
 | `substring` | ✅ | Native |  |
 | `substring_index` | ✅ | Native |  |
 | `to_binary` | ✅ | — | The hex form runs natively; the base64 and `utf-8` forms route through the JVM codegen dispatcher |
-| `to_char` | ✅ | Codegen dispatch |  |
+| `to_char` | ✅ | — |  |
 | `to_number` | ✅ | Codegen dispatch |  |
-| `to_varchar` | ✅ | Codegen dispatch |  |
+| `to_varchar` | ✅ | — |  |
 | `translate` | ✅ | Hybrid | Codegen dispatch by default: DataFusion's `translate` iterates over Unicode graphemes (Spark uses code points) and substitutes U+0000 instead of treating it as a deletion sentinel, so the native path is opt-in via allowIncompatible |
 | `trim` | ✅ | Native |  |
 | `try_to_binary` | ✅ | — | Rewrites to `try_eval(to_binary(...))`, which routes through the JVM codegen dispatcher |
 | `try_to_number` | ✅ | Codegen dispatch | Routed through the JVM codegen dispatcher |
 | `ucase` | ✅ | Hybrid |  |
-| `unbase64` | ✅ | Codegen dispatch | Column or literal input runs natively; other child expressions, and the strict form used by `to_binary(str, 'base64')`, route through the JVM codegen dispatcher |
+| `unbase64` | ✅ | Hybrid | Column or literal input runs natively; other child expressions, and the strict form used by `to_binary(str, 'base64')`, route through the JVM codegen dispatcher |
 | `upper` | ✅ | Hybrid |  |
 
 ---


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org