11---
22name : audit-comet-expression
3- description : Audit an existing Comet expression for correctness and test coverage. Studies the Spark implementation across versions 3.4.3, 3.5.8, and 4.0 .1, reviews the Comet and DataFusion implementations, identifies missing test coverage, and offers to implement additional tests.
3+ description : Audit an existing Comet expression for correctness and test coverage. Studies the Spark implementation across versions 3.4.3, 3.5.8, 4.0.1, and 4.1 .1, reviews the Comet and DataFusion implementations, identifies missing test coverage, and offers to implement additional tests.
44argument-hint : <expression-name>
55---
66
@@ -10,7 +10,7 @@ Audit the Comet implementation of the `$ARGUMENTS` expression for correctness an
1010
1111This audit covers:
1212
13- 1 . Spark implementation across versions 3.4.3, 3.5.8, and 4.0 .1
13+ 1 . Spark implementation across versions 3.4.3, 3.5.8, 4.0.1, and 4.1 .1
14142 . Comet Scala serde implementation
15153 . Comet Rust / DataFusion implementation
16164 . Existing test coverage (Comet SQL Tests and Comet Scala Tests)
@@ -24,7 +24,7 @@ Clone specific Spark version tags (use shallow clones to avoid polluting the wor
2424
2525``` bash
2626set -eu -o pipefail
27- for tag in v3.4.3 v3.5.8 v4.0.1; do
27+ for tag in v3.4.3 v3.5.8 v4.0.1 v4.1.1 ; do
2828 dir=" /tmp/spark-${tag} "
2929 if [ ! -d " $dir " ]; then
3030 git clone --depth 1 --branch " $tag " https://github.com/apache/spark.git " $dir "
3737Search the Catalyst SQL expressions source:
3838
3939``` bash
40- for tag in v3.4.3 v3.5.8 v4.0.1; do
40+ for tag in v3.4.3 v3.5.8 v4.0.1 v4.1.1 ; do
4141 dir=" /tmp/spark-${tag} "
4242 echo " === $tag ==="
4343 find " $dir /sql/catalyst/src/main/scala" -name " *.scala" | \
4848If the expression is not found in catalyst, also check core:
4949
5050``` bash
51- for tag in v3.4.3 v3.5.8 v4.0.1; do
51+ for tag in v3.4.3 v3.5.8 v4.0.1 v4.1.1 ; do
5252 dir=" /tmp/spark-${tag} "
5353 echo " === $tag ==="
5454 find " $dir /sql" -name " *.scala" | \
@@ -73,6 +73,7 @@ Produce a concise diff summary of what changed between:
7373
7474- 3.4.3 → 3.5.8
7575- 3.5.8 → 4.0.1
76+ - 4.0.1 → 4.1.1
7677
7778Pay attention to:
7879
@@ -87,7 +88,7 @@ Pay attention to:
8788## Step 2: Locate the Spark Tests
8889
8990``` bash
90- for tag in v3.4.3 v3.5.8 v4.0.1; do
91+ for tag in v3.4.3 v3.5.8 v4.0.1 v4.1.1 ; do
9192 dir=" /tmp/spark-${tag} "
9293 echo " === $tag ==="
9394 find " $dir /sql" -name " *.scala" -path " */test/*" | \
@@ -208,6 +209,11 @@ and in EXPLAIN output, so they are user-facing.
208209- Use backticks around config keys, type names, and SQL identifiers.
209210- Link to a tracking GitHub issue for known incompatibilities so users can
210211 follow progress: ` (https://github.com/apache/datafusion-comet/issues/NNNN) ` .
212+ ** Verify the issue exists and is open** before citing it
213+ (` gh issue view <N> --repo apache/datafusion-comet ` ). Issue numbers
214+ invented from context or recalled from memory are a recurring failure
215+ mode: a stale link is worse than no link because the reader follows it
216+ and finds nothing.
211217- Keep it concise. Single sentence is best.
212218- Do not write "Incompatible reason: ..." or "Unsupported because ...".
213219 The doc generator adds the framing.
@@ -389,6 +395,49 @@ finding for Step 6.
389395 read like internal implementation notes ("DataFusion probes the longer
390396 side") or that mismatch their support level (an "Incompatible" reason
391397 that says "X is not supported").
398+ 10 . ** Expression-shape restrictions live in ` getSupportLevel ` .** Any
399+ restriction that is knowable from the expression alone (literal-only
400+ arguments, unsupported child data type, foldable-only options, a
401+ specific operator shape) must be declared as an
402+ ` Unsupported(Some(reason)) ` branch in ` getSupportLevel ` , not gated
403+ inside ` convert ` with a ` withInfo ` + ` return None ` . Putting the
404+ check in ` convert ` means EXPLAIN surfaces the reason only at
405+ conversion time, the doc generator never sees it, and the
406+ dispatcher cannot route around it. The literal-only ` len `
407+ restrictions on ` CometLeft ` , ` CometRight ` , and ` CometSubstring `
408+ are the canonical example of the in-` convert ` pattern that this
409+ skill forbids: lift them into ` getSupportLevel ` .
410+ 11 . ** Spark 4.0 collation divergences are flagged, not glossed over.**
411+ If the Spark 4.0/4.1 implementation routes through
412+ ` CollationSupport.X.exec(..., collationId) ` (or uses
413+ ` StringTypeWithCollation ` / ` StringTypeNonCSAICollation ` for input
414+ types) and the Comet path does not propagate collation, the
415+ expression is ` Incompatible ` for non-default collations. Mark the
416+ branch ` Incompatible(Some(reason)) ` linking to the collation
417+ umbrella issue
418+ (https://github.com/apache/datafusion-comet/issues/4496 ) so the
419+ follow-up sweep can find every site. "Behaviour unchanged for
420+ ` UTF8_BINARY ` " alone is not a justification for leaving the
421+ support level at ` Compatible ` : users running with non-default
422+ collations get silently wrong answers.
423+ 12 . ** Known divergences flip the support level.** If you find yourself
424+ writing the words "Known divergence" or "Known limitation" in the
425+ support-doc sub-bullet while leaving ` getSupportLevel ` returning
426+ ` Compatible ` , the audit has skipped its job. A documented
427+ divergence is by definition not ` Compatible ` . Promote the branch
428+ to ` Incompatible(Some(reason)) ` (or ` Unsupported ` if the native
429+ path errors rather than producing a wrong answer) and link the
430+ tracking issue. The ` replace ` empty-search-string divergence with
431+ DataFusion is the canonical example of this anti-pattern.
432+ 13 . ** Unreachable serde mappings are removed.** Expressions registered
433+ as ` RuntimeReplaceable ` (or otherwise rewritten by an analyzer
434+ rule before serde) never reach ` QueryPlanSerde.exprToProtoInternal `
435+ with their original class. If the audit finds that a registered
436+ ` CometScalarFunction("name") ` or ` CometExpressionSerde ` entry can
437+ never be hit (e.g. the ` btrim ` mapping for ` StringTrimBoth ` , which
438+ is rewritten to ` StringTrim ` before serde runs), delete the
439+ registration in the same audit PR. Documenting the dead code in
440+ the support doc is not enough.
392441
393442---
394443
@@ -411,6 +460,11 @@ For an untested case, run it manually first to determine the current
411460behaviour, then commit either a regression test (passes) or a
412461` query ignore(<issue-url>) ` test (fails).
413462
463+ Every item in this bucket either becomes an inline fix + test, or a
464+ filed GitHub issue + ignored regression test, in the audit PR. Step 7
465+ spells out the workflow: never leave a high-priority finding as PR-body
466+ prose only.
467+
414468### Medium priority: missing test coverage
415469
416470Low-risk coverage gaps: additional input permutations on already-tested
@@ -429,9 +483,13 @@ etc. These come from the Step 5 consistency audit.
429483
430484High-priority findings (correctness divergences and high-risk coverage
431485gaps) and consistency issues from Step 5 / Step 6 must not be left as
432- prose. Apply them in the same PR as the audit. Only low-risk missing
433- coverage requires the user's go-ahead, because adding tests for cases
434- that already work on well-exercised paths is incremental polish.
486+ prose. Apply them in the same PR as the audit. Anything you cannot fix
487+ inline (because it needs a semantics decision, native code change, or
488+ larger design work) must still be captured as a GitHub issue per the
489+ "Findings that need follow-up" section below: prose recommendations in
490+ the PR body alone are insufficient. Only low-risk missing coverage
491+ requires the user's go-ahead, because adding tests for cases that
492+ already work on well-exercised paths is incremental polish.
435493
436494### High-priority findings: capture as tests
437495
@@ -499,16 +557,80 @@ need user approval. The classes of fix are:
499557- Hoist a reason shared by multiple serdes (e.g. a recurring
500558 TimestampNTZ caveat) into a small ` private object ` companion in the
501559 same file, mirroring ` UTCTimestampSerde ` .
560+ - Lift expression-shape restrictions (literal-only argument, foldable
561+ child, unsupported child data type) out of ` convert ` 's ` withInfo ` +
562+ ` return None ` and into an ` Unsupported(Some(reason)) ` branch in
563+ ` getSupportLevel ` . The ` convert ` body should then assume the
564+ precondition holds and stop calling ` withInfo ` for that case.
565+ - Promote a documented "Known divergence" or "Known limitation" sub-
566+ bullet from a ` Compatible ` branch to ` Incompatible(Some(reason)) `
567+ (or ` Unsupported ` if the native path errors) and link the tracking
568+ issue. The sub-bullet stays as user-facing documentation. The
569+ support level catches up to match.
570+ - Mark expressions whose Spark 4.0+ path routes through
571+ ` CollationSupport.X.exec ` (or accepts ` StringTypeWithCollation ` /
572+ ` StringTypeNonCSAICollation ` ) as ` Incompatible(Some(reason)) ` for
573+ non-default collations, linking
574+ https://github.com/apache/datafusion-comet/issues/4496 .
575+ - Delete unreachable serde registrations (` RuntimeReplaceable ` rewrites
576+ the expression before serde runs, an analyzer rule strips the case,
577+ etc.) rather than documenting them as a curiosity.
502578
503579Each fix is one of these patterns. If a finding requires a semantics
504580decision (e.g. is a specific branch really ` Unsupported ` , or is it
505- ` Incompatible ` ?), do not guess: leave it as a prose recommendation in
506- the PR description and call it out for the reviewer.
581+ ` Incompatible ` ?), do not guess: ** file a GitHub issue per the
582+ "Findings that need follow-up" section below** and link it from the PR
583+ description. Do not leave the recommendation as prose only: prose in a
584+ PR description gets buried as soon as the PR merges.
507585
508586After every fix, build the affected module to make sure the edit
509587compiles. Do not run the full suite; targeted tests suffice if the
510588fix could plausibly affect behaviour.
511589
590+ ### Findings that need follow-up: always file a tracking issue
591+
592+ Any high-priority finding (correctness divergence, robustness gap,
593+ behavioural difference from Spark, missing-collation guard, etc.) that
594+ this PR does not fix inline ** must** be filed as a GitHub issue before
595+ the PR is opened. This includes:
596+
597+ - Semantics decisions the audit surfaces but should not unilaterally
598+ resolve (e.g. promote ` Compatible ` to ` Incompatible ` , change a
599+ default).
600+ - Architectural concerns that span multiple expressions (e.g. Spark 4.0
601+ collation propagation across an entire family).
602+ - Bugs that are fixable in principle but need more design or native
603+ changes than fit in the audit PR.
604+ - Documentation gaps surfaced by the audit (e.g. an expression that
605+ doesn't appear in the auto-generated compatibility doc).
606+
607+ For each follow-up:
608+
609+ 1 . Search for an existing issue first
610+ (` gh issue list --search "<expression> <symptom> in:title,body" --state all --limit 5 ` ).
611+ If a candidate match comes back, ** open it
612+ (` gh issue view <N> --repo apache/datafusion-comet ` ) and confirm the
613+ title and body actually describe the divergence you found, and that
614+ the issue is still ` OPEN ` ** . A closed-but-fixed issue cited as
615+ "known divergence" is worse than no citation, because the reader
616+ follows the link and finds a fix that was already shipped. If it
617+ matches, link it from the PR description and the support-doc
618+ sub-bullet, and stop.
619+ 2 . If no issue exists, file one with ` gh issue create ` using the
620+ ` correctness ` label (or ` documentation ` for doc-only gaps) plus any
621+ relevant area labels (e.g. ` spark 4.0 ` ). Title format:
622+ ` [Bug] <expression> <one-line symptom> ` . Body includes: Spark version
623+ range affected, a minimal repro, the divergent result, the relevant
624+ Comet file/line, and a one-line note that the issue was surfaced by
625+ this audit PR.
626+ 3 . Reference the issue number from both the support-doc sub-bullet and
627+ the PR description "What changes are included" section so reviewers
628+ can see what work the audit intentionally deferred.
629+
630+ Prose-only "future work" notes in the PR description are not enough.
631+ The whole point of the audit is to leave behind durable artefacts; an
632+ unfiled finding evaporates after the PR merges.
633+
512634### Low-risk missing test coverage: ask the user
513635
514636This is the only Step 7 category that pauses for user input. It only
@@ -592,7 +714,7 @@ used for the expression in `docs/source/user-guide/latest/expressions.md`.
592714 other pages.
593715- Add (or update) a ` ## <function_name> ` section, keeping sections alphabetically ordered.
594716- Under that heading, add one bullet per Spark version checked, each including:
595- - Spark version (e.g. 3.4.3, 3.5.8, 4.0.1)
717+ - Spark version (e.g. 3.4.3, 3.5.8, 4.0.1, 4.1.1 )
596718 - Today's date
597719 - A brief note for any version-specific finding (behavioral difference, known
598720 incompatibility); omit the note if nothing notable.
@@ -604,7 +726,7 @@ used for the expression in `docs/source/user-guide/latest/expressions.md`.
604726Present the audit as:
605727
6067281 . ** Expression Summary** - Brief description of what ` $ARGUMENTS ` does, its input/output types, and null behavior
607- 2 . ** Spark Version Differences** - Summary of any behavioral or API differences across Spark 3.4.3, 3.5.8, and 4.0 .1
729+ 2 . ** Spark Version Differences** - Summary of any behavioral or API differences across Spark 3.4.3, 3.5.8, 4.0.1, and 4.1 .1
6087303 . ** Comet Implementation Notes** - Summary of how Comet implements this expression and any concerns
6097314 . ** Coverage Gap Analysis** - The gap table from Step 5, plus implementation gaps
6107325 . ** Recommendations** - Prioritized list from Step 6
0 commit comments