Conversation
The scikit-learn estimators are fitted on one port and score on the other, so the script holds both frames and narrows each by the same rule: a fit and a score taken on different columns would compare two different models. The four Hugging Face models declare the column types they take, and the iris regression keeps the row when a petal measurement is empty rather than ending the run on it. Sklearn Prediction and Sklearn Testing are reported as unverifiable rather than exported blind: each consumes a fitted model on an input port, and a fixture written from the JVM cannot carry a live Python object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Automated Reviewer SuggestionsBased on the
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8368 +/- ##
============================================
- Coverage 92.78% 92.77% -0.01%
+ Complexity 4899 4890 -9
============================================
Files 1236 1236
Lines 52130 52103 -27
Branches 6407 6405 -2
============================================
- Hits 48369 48340 -29
- Misses 2185 2186 +1
- Partials 1576 1577 +1
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 522 | 0.319 | 18,737/25,031/25,031 us | 🔴 -9.8% / 🔴 +61.9% |
| 🔴 | bs=100 sw=10 sl=64 | 1,197 | 0.731 | 78,959/114,298/114,298 us | 🔴 +18.7% / 🟢 -21.1% |
| ⚪ | bs=1000 sw=10 sl=64 | 1,410 | 0.861 | 706,280/778,035/778,035 us | ⚪ within ±5% / 🟢 +33.6% |
Baseline details
Latest main 5264df2 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 522 tuples/sec | 579 tuples/sec | 796.29 tuples/sec | -9.8% | -34.4% |
| bs=10 sw=10 sl=64 | MB/s | 0.319 MB/s | 0.353 MB/s | 0.486 MB/s | -9.6% | -34.4% |
| bs=10 sw=10 sl=64 | p50 | 18,737 us | 17,436 us | 12,549 us | +7.5% | +49.3% |
| bs=10 sw=10 sl=64 | p95 | 25,031 us | 23,800 us | 15,458 us | +5.2% | +61.9% |
| bs=10 sw=10 sl=64 | p99 | 25,031 us | 23,800 us | 19,275 us | +5.2% | +29.9% |
| bs=100 sw=10 sl=64 | throughput | 1,197 tuples/sec | 1,227 tuples/sec | 1,027 tuples/sec | -2.4% | +16.6% |
| bs=100 sw=10 sl=64 | MB/s | 0.731 MB/s | 0.749 MB/s | 0.627 MB/s | -2.4% | +16.6% |
| bs=100 sw=10 sl=64 | p50 | 78,959 us | 81,805 us | 100,085 us | -3.5% | -21.1% |
| bs=100 sw=10 sl=64 | p95 | 114,298 us | 96,317 us | 105,895 us | +18.7% | +7.9% |
| bs=100 sw=10 sl=64 | p99 | 114,298 us | 96,317 us | 116,076 us | +18.7% | -1.5% |
| bs=1000 sw=10 sl=64 | throughput | 1,410 tuples/sec | 1,366 tuples/sec | 1,055 tuples/sec | +3.2% | +33.6% |
| bs=1000 sw=10 sl=64 | MB/s | 0.861 MB/s | 0.833 MB/s | 0.644 MB/s | +3.4% | +33.6% |
| bs=1000 sw=10 sl=64 | p50 | 706,280 us | 731,549 us | 979,292 us | -3.5% | -27.9% |
| bs=1000 sw=10 sl=64 | p95 | 778,035 us | 785,016 us | 1,018,835 us | -0.9% | -23.6% |
| bs=1000 sw=10 sl=64 | p99 | 778,035 us | 785,016 us | 1,039,692 us | -0.9% | -25.2% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,382.95,200,128000,522,0.319,18737.39,25030.72,25030.72
1,100,10,64,20,1670.75,2000,1280000,1197,0.731,78958.66,114298.22,114298.22
2,1000,10,64,20,14182.18,20000,12800000,1410,0.861,706279.54,778035.12,778035.12
carloea2
left a comment
There was a problem hiding this comment.
Sklearn Testing drops rows with missing values in the engine path, but the standalone code uses all rows. Missing values can make the script fail or produce different scores. Please apply the same filtering before building X and Y, and add a parity test with a missing row.
The executor drops every row holding a missing value before it scores, because the model arrives already fitted and the operator cannot ask which estimator it holds. The exported script scored all of them, so it answered with a number the run never reported, or failed inside scikit-learn on a value the estimator refuses. The verification runner cannot catch this one: a fixture written from the JVM cannot carry a fitted model on an input port, so the two paths are never run side by side. The test instead pins the property that follows from the drop, which is testable on its own: a row the executor would drop must not move the score. Its label is one the model never saw, so scoring that row is wrong whatever the estimator answers; a plausible label would have agreed by luck, since a decision tree predicts through a missing feature rather than refusing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Fixed. The script drops the rows the executor drops before it builds X and Y. The test pins that a dropped row cannot move the score, since this operator cannot be run against the other path (a JVM fixture cannot carry a fitted model on an input port). |
carloea2
left a comment
There was a problem hiding this comment.
The generated code now drops the same missing rows as the executor. The test covers it.
…ault These four say `producesDataFrame = true`, which is what the trait already returns. The neighbours that override it are charts, which return false, so saying it here reads as a distinction rather than as the no-op it is. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The shared table renames the columns whose names hold the characters that end a Python literal. These annotations name one, and are test-only: they steer which column a parity run fills the field with, and have no effect in production. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
carloea2
left a comment
There was a problem hiding this comment.
Reviewed alongside the related export and verification PRs. These findings are based on code inspection and focused Python checks, not a full Scala suite run.
The executor takes a row at a time and leaves the result empty where a feature is missing, so the row keeps its place. One call over the whole frame cannot do that: scikit-learn ends the run on the first missing value. Predict on the complete rows and write those answers back where they came from. Both ground truth branches needed it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@carloea2 the finding is fixed: prediction runs per row, so a row with a missing feature keeps its place with an empty result. Would you take another look when you have a moment? |
carloea2
left a comment
There was a problem hiding this comment.
Missing feature rows now stay in place with an empty prediction. Complete rows are predicted together. Looks good.
carloea2
left a comment
There was a problem hiding this comment.
The sentiment, spam, and summarization exports only check None and blank strings. A missing pandas text value can be NaN or pd.NA, which is passed to the model and fails. Please handle all pandas missing values and add tests.
carloea2
left a comment
There was a problem hiding this comment.
Sklearn Testing calls predict on X.squeeze. One feature across several rows or one remaining row across several features becomes one dimensional and sklearn rejects it. Please keep X two dimensional in both paths and test both shapes.
…ing text cell as NaN SklearnTesting squeezed the feature frame before predicting, which collapsed a single feature, or a single row left by the drop, to one dimension. scikit-learn rejects both. The executor and the exported script each pass the frame itself now. The three HuggingFace text operators guarded a missing cell with `is None`. That holds for the executor, which reads a tuple, but the exported script reads a frame, where a column holding nothing else comes back as float64 and its cells as NaN. The script now asks pandas. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cutor side too The three HuggingFace text operators compared the cell to None. That is right for an empty cell, which Arrow normalizes to null whatever pandas sent, but the attributeTypeRules naming the column string is a warning the editor prints rather than a filter, so a numeric column can be chosen and reaches the executor carrying its own NaN. Both paths ask pandas now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both paths now ask |
|
Both paths now hand predict the frame itself rather than squeezing it first. The spec scores a single-feature table and a table with one surviving row, and asserts that neither path still squeezes. |
carloea2
left a comment
There was a problem hiding this comment.
Sklearn Testing scores only the first model in the exported path and copies that score to every model row. With two classifiers where one predicts 0 and one predicts 1 against labels 0 and 0, native returns accuracy 1.0 and 0.0, but the export returns 1.0 for both. Please score each model row separately and add a two model test.
Sklearn Testing scored with the first model the port carried and wrote that one number down every row, where the executor scores each model row on its own. Sklearn Prediction read the first row as well, where the executor keeps the last model the port hands it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Fixed in f9835ba: the exported script now predicts once per model row, and the new two model test reads 1.0 and 0.0 where it used to read 1.0 twice. Sklearn Prediction read the first model too, where the executor keeps the last one the port hands it, so that is in the same commit. |
carloea2
left a comment
There was a problem hiding this comment.
The missing value, input shape, and multiple model issues are fixed. Each model now gets its own scores. I checked the two model case and found no remaining blocker in this review.
The operator runs once per port and says how many rows it dropped each time, so a run whose testing table also has holes reports two counts. The exported script said it for the table it fits and not for the one it scores, so the same run reported one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
carloea2
left a comment
There was a problem hiding this comment.
The added reporting matches the native handling of skipped test rows. The previously reviewed model fixes remain intact. Looks good.
What changes were proposed in this PR?
The scikit-learn estimators are fitted on one port and score on the other, so
the script holds both frames and narrows each by the same rule: a fit and a
score taken on different columns would compare two different models.
The four Hugging Face models declare the column types they take, and the iris
regression keeps the row when a petal measurement is empty rather than ending
the run on it.
Sklearn Prediction and Sklearn Testing are reported as unverifiable rather
than exported blind: each consumes a fitted model on an input port, and a
fixture written from the JVM cannot carry a live Python object.
Review also turned up two defects that this PR fixes rather than mirrors.
SklearnTestingsqueezed the feature frame before predicting, so a single feature column, or the single row a drop left behind, reached scikit-learn as one dimension and was rejected. That was the executor's own behaviour and the export had copied it, so both paths pass the frame itself now. Separately, the three HuggingFace text operators guarded a missing cell withis None. Arrow normalizes an empty cell to null, so that held for the executor as long as the column really was a string, butattributeTypeRulesis a warning the editor prints rather than a filter, and the exported script reads a frame where a column holding nothing else comes back as float64. Both paths ask pandas now.Any related issues, documentation, discussions?
Part of #8325, 20 of 27; that issue lists the set in order. It needs #8327 for the trait, so it does not compile until that lands, and the rows these operators add to the verification runner follow with the harness rather than as whole new files here.
Closes #8316, closes #8056.
Closes #8422, the task this change is the whole of.
How was this PR tested?
Each operator asserts the block it emits in its own spec. Once the harness lands, each is also run through the engine and through its generated script, on every configuration its schema offers, and the two answers compared.
Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)