Skip to content

feat!: validate default evaluator input schemas at top level - #3274

Open
dengsh12 wants to merge 7 commits into
delta-io:mainfrom
dengsh12:validate-evaluator-input-schema
Open

feat!: validate default evaluator input schemas at top level#3274
dengsh12 wants to merge 7 commits into
delta-io:mainfrom
dengsh12:validate-evaluator-input-schema

Conversation

@dengsh12

@dengsh12 dengsh12 commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

What changes are proposed in this pull request?

Short term solution mentioned in #3263

How was this change tested?

positive test: all kernel data types; nested mismatches
negative test: all validation failure cases including missing, mismatching fields

@github-actions github-actions Bot added the breaking-change Public API change that could cause downstream compilation failures. Requires a major version bump. label Sep 8, 2026
@dengsh12 dengsh12 changed the title feat: validate input schema vs data schema in DefaultExpressionEvaluator feat!: validate evaluator input schemas Sep 8, 2026
@dengsh12
dengsh12 force-pushed the validate-evaluator-input-schema branch from 92b9a70 to 0b9a1ab Compare September 9, 2026 01:42
@github-actions github-actions Bot removed the breaking-change Public API change that could cause downstream compilation failures. Requires a major version bump. label Sep 9, 2026
@github-actions github-actions Bot added the breaking-change Public API change that could cause downstream compilation failures. Requires a major version bump. label Sep 9, 2026
@codecov

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.70079% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.36%. Comparing base (1091824) to head (148f199).
⚠️ Report is 17 commits behind head on main.

Files with missing lines Patch % Lines
kernel/src/transaction/mod.rs 91.89% 1 Missing and 2 partials ⚠️
kernel/src/engine/arrow_expression/mod.rs 93.93% 0 Missing and 2 partials ⚠️
kernel/src/log_reader/checkpoint_manifest.rs 93.75% 1 Missing ⚠️
kernel/src/parallel/sequential_phase.rs 87.50% 0 Missing and 1 partial ⚠️
kernel/src/scan/mod.rs 94.73% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3274      +/-   ##
==========================================
+ Coverage   90.26%   90.36%   +0.10%     
==========================================
  Files         251      250       -1     
  Lines       88309    89231     +922     
  Branches    88309    89231     +922     
==========================================
+ Hits        79710    80632     +922     
+ Misses       5727     5660      -67     
- Partials     2872     2939      +67     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dengsh12
dengsh12 marked this pull request as ready for review September 11, 2026 01:04
@dengsh12 dengsh12 changed the title feat!: validate evaluator input schemas feat!: validate default evaluator input schemas at top level Sep 11, 2026
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown

Benchmark results: ✅ Pass

Summary: 🚀 0  ·  ✅ 8  ·  ☑️ 2  ·  🚧 5  ·  ❌ 0

Per-benchmark results (15 rows)
Test Change Base PR
clustered/readMetadataLatestPredicate/serial 🚧 1.05x slower 103.7±1.73ms 108.8±2.48ms
crcLatest/snapshotLatest ☑️ 1.02x slower 10.6±0.42ms 10.8±0.24ms
crcMissing/snapshotLatest ✅ 1.02x faster 25.6±0.62ms 25.2±0.67ms
crcSlightlyStale/snapshotLatest ✅ 1.00x 11.7±0.31ms 11.7±0.27ms
crcVeryStale/snapshotLatest ✅ 1.00x 17.4±0.39ms 17.4±0.56ms
partitioned/readMetadataLatestPredicate/serial 🚧 1.05x slower 60.4±3.46ms 63.5±1.62ms
v1Checkpoint/readMetadataLatest/serial ✅ 1.04x faster 13.5±0.40ms 13.0±0.17ms
v1Checkpoint/snapshotLatest ✅ 1.05x faster 886.3±36.84µs 841.6±36.35µs
v2Checkpoint/readMetadataLatest/parallel2 🚧 1.10x slower 9.6±0.51ms 10.6±0.55ms
v2Checkpoint/readMetadataLatest/serial ✅ 1.02x faster 15.5±0.30ms 15.2±0.24ms
v2Checkpoint/snapshotLatest ✅ 1.02x faster 876.5±40.46µs 859.2±38.73µs
wideSchemaJsonStats/readMetadataLatestPredicate/serial 🚧 1.05x slower 77.6±0.67ms 81.8±2.42ms
wideSchemaJsonStats/snapshotLatest ✅ 1.00x 2.4±0.03ms 2.4±0.05ms
wideSchemaStructStats/readMetadataLatestPredicate/serial ☑️ 1.02x slower 35.8±0.72ms 36.4±1.04ms
wideSchemaStructStats/snapshotLatest 🚧 1.05x slower 2.2±0.05ms 2.3±0.04ms

Legend: 🚀 ≥1.15x faster  · ✅ faster or unchanged  · ☑️ ≤1.03x slower  · 🚧 1.03x-1.15x slower  · ❌ ≥1.15x slower
Commit: 148f199 · Trigger: auto-push · Tags: base · Updated: 2026-09-11 15:31 PDT

@dengsh12
dengsh12 marked this pull request as draft September 11, 2026 03:06
@dengsh12
dengsh12 marked this pull request as ready for review September 11, 2026 22:22
}
}

fn validate_data_schema_top_level(

@dengsh12 dengsh12 Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if data_schema has two fields with same names, it won't be rejected here. AFAIK we must never create such arrow schema -- the validation seems unnecessary. But lmk if you think there is a need

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review (draft - human review required)

Show review

This PR turns on the previously dead top-level input-schema check in the default Arrow evaluator and threads explicit read schemas through the checkpoint, sequential, and remove-action paths. No blocking issues. The type-compatibility mappings (interval, variant, dictionary, list/map variants, string/int width normalization) line up with the kernel Arrow conversion in both directions, sidecar discovery still gets SIDECAR_FIELD, and the four-evaluator remove selection matches the producer field order. A few non-blocking notes follow.

Non-blocking notes

Nit3

kernel/src/engine/arrow_expression/mod.rs:446 (RIGHT). top_level_types_compatible hand-encodes the interval and variant relationships that are the inverse of the Arrow-to-kernel mapping already defined in arrow_conversion. The special cases are needed because conversion erases those logical distinctions, but the table is a second copy of that correspondence and will need updating whenever a new type or alias is added there. Raised by: architecture-reviewer. Suggested fix: consider co-locating the "which Arrow types normalize to kernel type X" knowledge with the conversion helpers so this check consumes it rather than restating it; not required for this change.


Automated review - workflow run

})?;
// Only the top-level type is validated. `try_from_arrow` translates the entire field, but
// we use it here to keep the validation simple.
let data_field = StructField::try_from_arrow(data_field.as_ref())?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit1 The comment says "Only the top-level type is validated," but StructField::try_from_arrow recursively converts the entire matched field. If a matched top-level field contains a nested Arrow type with no kernel equivalent (Duration, native Interval, Timestamp(Second, _), Time32/64, Decimal256), the conversion errors and the batch is rejected, even though only the container kind matters and the same type in an unmatched extra field is tolerated. It also runs a full nested translation per evaluate() call on the log-replay path. Low likelihood today since data originates from kernel reads, but it is a latent false-reject that contradicts the stated intent. Raised by: maintainer-claude-reviewer, delta-protocol-reviewer. Suggested fix: classify on the Arrow DataType discriminant (Struct/List/.../Map/primitive) and convert only the top-level/leaf type, and add a test with a nested non-convertible Arrow type under a matched struct field.

let remove_actions = self.generate_remove_actions(
engine,
self.dv_matched_files.iter(),
true, /* has_dv_update_columns */

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit2 The DV-update path calls generate_remove_actions(..., true /* has_dv_update_columns */), but every update_deletion_vectors test builds its scan without stats_parsed/partitionValues_parsed, so only evaluator index 0 is exercised. The (true,false), (false,true), and (true,true) branches of scan_row_input_schema(_, _, true) are constructed but never evaluated against real data. Raised by: test-coverage-reviewer. Suggested fix: parametrize a DV-update integration test with StatsOptions/PartitionValuesOptions (mirroring test_remove_files_partitioned_with_parsed_columns), or add a unit test asserting scan_row_input_schema(true, true, true) yields exactly the scan-row fields plus stats_parsed, partitionValues_parsed, and the two DV columns.

Ok(())
}

fn top_level_types_compatible(expected_type: &DataType, data_type: &DataType) -> bool {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit3 top_level_types_compatible hand-encodes the interval and variant relationships that are the inverse of the Arrow-to-kernel mapping already defined in arrow_conversion. The special cases are needed because conversion erases those logical distinctions, but the table is a second copy that will need updating whenever a new type or alias is added there. Raised by: architecture-reviewer. Suggested fix: consider co-locating the "which Arrow types normalize to kernel type X" knowledge with the conversion helpers so this check consumes it rather than restating it; not required for this change.

.collect::<Vec<_>>()
))
})?;
// Only the top-level type is validated. `try_from_arrow` translates the entire field, but

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O(schema) translation, from the PR benchmark seems the perf impact not observable? we will do O(schema) validation anyway in future...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Public API change that could cause downstream compilation failures. Requires a major version bump.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant