Skip to content

fix: resolve current model metadata deterministically - #2632

Merged
Brendan Walsh (BrendanWalsh) merged 6 commits into
microsoft:masterfrom
ranadeepsingh:copilot/issue-1697-metric-metadata
Aug 17, 2026
Merged

fix: resolve current model metadata deterministically#2632
Brendan Walsh (BrendanWalsh) merged 6 commits into
microsoft:masterfrom
ranadeepsingh:copilot/issue-1697-metric-metadata

Conversation

@ranadeepsingh

@ranadeepsingh Rana Singh (ranadeepsingh) commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #1697.

ComputeModelStatistics now resolves scored-model metadata deterministically after repeated training/evaluation in the same DataFrame lineage. It ignores orphaned entries, collapses semantically equivalent duplicates, rejects conflicting metadata independently of column order, honors complete explicit settings, and reports actionable missing/ambiguous column errors instead of reaching col(null).

Key changes

  • Build a one-pass immutable index of score-model metadata rather than selecting the first schema/metadata entry.
  • Require compatible label + prediction metadata and valid classification/regression kind.
  • De-duplicate equivalent model IDs by semantic column signature and sort all diagnostics.
  • Detect conflicting label/prediction/raw-score/probability roles deterministically.
  • Preserve explicit classification/regression columns when they fully define evaluation.
  • Resolve columns with Spark case-sensitivity semantics and validate them before expression construction.
  • Keep classification score lookup lazy for score-independent metrics.
  • Preserve uid/params through copy, pipelines, and serialization via defaultCopy.
  • Replay merged feat(core): add precision-recall AUC metric #2635 as a Spark 4.1 release-compatibility prerequisite.

Coverage

Added regression and negative coverage for:

  • regressor → classifier reuse with stale lineage metadata;
  • explicit columns versus unrelated/ambiguous metadata;
  • equivalent duplicates and conflicting roles;
  • schema column-order independence;
  • missing/default/invalid columns and lazy score validation;
  • classification and regression behavior;
  • copy, PipelineModel, serialization, getters, codegen, and Python wrapper surface;
  • feat(core): add precision-recall AUC metric #2635 binary metric/schema ordering interactions.

Validation

  • JDK 11 VerifyComputeModelStatistics: 32/32 passed.
  • JDK 11 VerifyComputePerInstanceStatistics: 5/5 passed.
  • JDK 11 core compile + test compile: passed.
  • Scala style + test style: passed.
  • Serialization fuzzing + getters/setters: passed.
  • core/codegen: passed; generated ComputeModelStatistics.py compiles.
  • Black 22.3.0: 189 files unchanged.
  • CI pytest tools/ci/tests/test_pipeline_yaml.py: 59/59 passed.
  • Exact Spark 4.1 replay with configured prerequisites and JDK 17 test:compile: passed.

No existing public method signature was removed or changed; the original MetricUtils.getSchemaInfo and ComputeModelStatistics.copy signatures remain intact.

Copilot AI lite review requested due to automatic review settings August 14, 2026 22:07
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@github-actions

Copy link
Copy Markdown

Hey Rana Singh (@ranadeepsingh) 👋!
Thank you so much for contributing to our repository 🙌.
Someone from SynapseML Team will be reviewing this pull request soon.

We use semantic commit messages to streamline the release process.
Before your pull request can be merged, you should make sure your first commit and PR title start with a semantic prefix.
This helps us to create release messages and credit you for your hard work!

Examples of commit messages with semantic prefixes:

  • fix: Fix LightGBM crashes with empty partitions
  • feat: Make HTTP on Spark back-offs configurable
  • docs: Update Spark Serving usage
  • build: Add codecov support
  • perf: improve LightGBM memory usage
  • refactor: make python code generation rely on classes
  • style: Remove nulls from CNTKModel
  • test: Add test coverage for CNTKModel

To test your commit locally, please follow our guild on building from source.
Check out the developer guide for additional guidance on testing your change.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes non-deterministic scored-model metadata resolution in the core metrics pipeline, preventing ComputeModelStatistics from selecting stale model metadata across repeated training/evaluation within the same DataFrame lineage (as reported in #1697).

Changes:

  • Make MetricUtils.getSchemaInfo deterministically enumerate, de-duplicate, and sort scored-model metadata candidates, filtering to complete (label + valid kind + prediction) candidates and rejecting ambiguity with guidance.
  • Add early, actionable column validation in ComputeModelStatistics to avoid constructing Spark expressions with unresolved/null columns, while keeping classification score resolution lazy for score-irrelevant metrics.
  • Add targeted regression tests covering stale metadata scenarios, explicit override precedence, deterministic ambiguity rejection, and improved error cases.
Show a summary per file
File Description
core/src/main/scala/com/microsoft/azure/synapse/ml/core/metrics/MetricUtils.scala Deterministic scored-model candidate discovery/selection and improved ambiguity/missing-metadata handling.
core/src/main/scala/com/microsoft/azure/synapse/ml/train/ComputeModelStatistics.scala Validates resolved label/prediction/score columns up-front with actionable errors; keeps score validation lazy for non-score metrics.
core/src/test/scala/com/microsoft/azure/synapse/ml/train/VerifyComputeModelStatistics.scala Adds focused tests for stale lineage metadata, explicit overrides, deterministic ambiguity failure, and score-column validation behavior.

Review details

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

Rana Singh (ranadeepsingh) pushed a commit to ranadeepsingh/SynapseML that referenced this pull request Aug 14, 2026
## Summary
Make the missing-metadata error mention the all-metrics restriction only when evaluationMetric is actually unresolved, and cover the explicit-metric/missing-label case.

## Prompting Intent
Address the actionable PR review comment without expanding issue microsoft#1697 scope, then re-run the focused JDK 11 test, compile, and style validation.

## Linked Sources
- GitHub issue: microsoft#1697
- Pull request: microsoft#2632
- Review comment: microsoft#2632 (comment)

## Rationale
Conditioning the hint on the unresolved setting avoids telling users to change a metric that is already explicit while preserving guidance when the default all-metrics mode is genuinely ambiguous.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 14, 2026 22:54
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.63%. Comparing base (60cf93c) to head (5cdf9ed).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2632      +/-   ##
==========================================
+ Coverage   88.60%   88.63%   +0.03%     
==========================================
  Files         331      331              
  Lines       18531    18556      +25     
  Branches     1752     1740      -12     
==========================================
+ Hits        16419    16447      +28     
+ Misses       2112     2109       -3     
Files with missing lines Coverage Δ
...ft/azure/synapse/ml/core/metrics/MetricUtils.scala 97.50% <100.00%> (+7.84%) ⬆️
...zure/synapse/ml/train/ComputeModelStatistics.scala 86.38% <100.00%> (+0.95%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

CI follow-up for latest SHA 5cdf9ed5ac47cd562582787502a4a8271c1c1641:

  • GitHub Actions and the code-relevant Azure UnitTests train job passed.
  • The initial Azure run (#231234591) had an unrelated transient Maven resolution failure in UnitTests lightgbm2; I retriggered /azp run, and that job passed on retry.
  • Retry run #231242691 completed with two unrelated live-service failures: UnitTests misc and UnitTests search1 both received HTTP 429 from mmlspark-azure-search because the shared service had reached its 50-index quota. The failing test was IndexSchemaLiveRoundTripSuite plus Azure Search writer suites; no changed metric/train code appears in either failure.

I did not delete shared Azure Search indexes to make the PR green. Diagnostic logs and the local JDK 11 validation evidence are retained in the requested issue artifact directory.

SynapseML CI and others added 4 commits August 16, 2026 00:28
Prevent ComputeModelStatistics from selecting orphaned model metadata left in dataframe lineage. Resolve complete scored-model candidates deterministically, honor explicit label and metric intent, reject genuine ambiguity, and report actionable missing-column errors.

Fix GitHub issue microsoft#1697 end to end while keeping the change focused and backward compatible. Reproduce repeated regression/classification training, preserve explicit column settings, cover ambiguous and missing metadata, and validate both classification and regression paths with JDK 11.

- GitHub issue: microsoft#1697

Enumerating complete label-plus-prediction metadata sets avoids relying on schema or metadata-map order and naturally excludes stale label-only entries. Explicit label and evaluation settings constrain selection without guessing. Ambiguous complete candidates fail with guidance rather than silently choosing a model, while generic Spark models retain the explicit-column fallback. Score validation remains lazy for metrics that do not consume scores to preserve existing behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary
Make the missing-metadata error mention the all-metrics restriction only when evaluationMetric is actually unresolved, and cover the explicit-metric/missing-label case.

## Prompting Intent
Address the actionable PR review comment without expanding issue microsoft#1697 scope, then re-run the focused JDK 11 test, compile, and style validation.

## Linked Sources
- GitHub issue: microsoft#1697
- Pull request: microsoft#2632
- Review comment: microsoft#2632 (comment)

## Rationale
Conditioning the hint on the unresolved setting avoids telling users to change a metric that is already explicit while preserving guidance when the default all-metrics mode is genuinely ambiguous.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary
Make scored-model discovery deterministic for duplicate, conflicting, incomplete, and reordered metadata; preserve fully explicit evaluation settings; validate columns with Spark case-sensitivity semantics; and retain parameters across copy, pipeline, and serialization paths.

## Prompting Intent
Make GitHub PR microsoft#2632 merge-ready after the microsoft#2635 metric changes by auditing metadata resolution, schema propagation, API compatibility, classification/regression behavior, pipeline serialization, code generation, determinism, concurrency safety, and performance, with robust end-to-end and negative tests.

## Linked Sources
- GitHub issue: microsoft#1697
- Pull request: microsoft#2632
- Interacting pull request: microsoft#2635
- Review comment: microsoft#2632 (comment)

## Rationale
A one-pass immutable metadata index removes schema-order dependence and avoids repeated model-by-model scans. Equivalent metadata is collapsed by semantic signature, conflicting required or score roles fail deterministically, orphaned entries remain ignorable, and complete explicit settings bypass unrelated metadata only when no metadata-derived column is needed. Package-scoped role lookup preserves the existing public API while preventing first-column selection, and defaultCopy preserves uid and params without changing the copy signature.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary
Add merged PR microsoft#2635 as a release-compatibility prerequisite so the metadata-resolution patch applies and compiles cleanly on the Spark 4.1 branch.

## Prompting Intent
Account for merged PR microsoft#2635 while making PR microsoft#2632 merge-ready, including an exact release-branch replay and Spark 4.1 test compilation rather than relying only on the master build.

## Linked Sources
- Pull request: microsoft#2632
- Prerequisite pull request: microsoft#2635
- GitHub issue: microsoft#1697

## Rationale
PR microsoft#2635 changed ComputeModelStatistics and its tests after Spark 4.1 diverged, so the PR-only patch conflicts without that baseline. Replaying the merged commit after the existing scoped test prerequisite matches the pipeline's prerequisite mechanism, keeps the feature patch focused, and was verified by an exact JDK 17 Spark 4.1 test:compile replay.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ranadeepsingh
Rana Singh (ranadeepsingh) force-pushed the copilot/issue-1697-metric-metadata branch from 5cdf9ed to dc55c79 Compare August 16, 2026 09:39
Copilot AI review requested due to automatic review settings August 16, 2026 09:39
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

## Summary
Teach release compatibility replay to include an add-only scoped baseline when a later unscoped prerequisite modifies that path, validate the scoped blob against the dependent commit's parent, and reset the release checkout before applying patches.

## Prompting Intent
Resolve the concrete Spark 4.1 Azure failure for PR microsoft#2632 without weakening prerequisite validation. The merged microsoft#2635 prerequisite depends on test files added by the existing scoped microsoft#2507 prerequisite even though those files are not directly changed by the PR.

## Linked Sources
- Pull request: microsoft#2632
- Failed Azure build: https://msdata.visualstudio.com/b9b2accc-2d1c-45b3-9d24-0eb5d78cc47f/_build/results?buildId=231383144
- Dependent prerequisite: microsoft#2635
- Scoped baseline prerequisite: microsoft#2507

## Rationale
The existing replay selected scoped prerequisites only by direct PR-path overlap, so microsoft#2635 was applied before its add-only test baseline and failed. Looking ahead only to later unscoped prerequisites preserves normal skip behavior for unrelated paths while replaying true dependencies in config order. Comparing the scoped blob to the first dependent prerequisite parent retains exact-baseline validation, and a hard reset removes checkout/index drift before three-way application.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 16, 2026 10:02
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

core/src/main/scala/com/microsoft/azure/synapse/ml/core/metrics/MetricUtils.scala:196

  • The ambiguity error suggests only setting labelCol and evaluationMetric, but callers may already have both set and still hit this when multiple candidates share the same label/kind (e.g., differing prediction/raw columns). The message should also guide users toward specifying columns explicitly (or clearing stale metadata) so the next action is clear.
        throw new IllegalArgumentException(
          "Ambiguous scored-model metadata. Multiple complete candidates match: " +
            candidates.map(_.description).mkString("[", ", ", "]. ") +
            "Set labelCol and evaluationMetric to select one candidate; remove stale score metadata if needed.")
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread pipeline.yaml Outdated
Rana Singh (ranadeepsingh) pushed a commit to ranadeepsingh/SynapseML that referenced this pull request Aug 16, 2026
## Summary
Resolve configured label columns using Spark case-sensitivity semantics across model and per-instance statistics, improve ambiguous metadata guidance, and remove non-portable Bash negative array indexing from release replay.

## Prompting Intent
Address every final Copilot review comment on PR microsoft#2632 while preserving deterministic metadata selection, schema propagation, compatibility, and Spark 4.1 replay behavior.

## Linked Sources
- Pull request: microsoft#2632
- GitHub issue: microsoft#1697
- Case-resolution review: microsoft#2632 (comment)
- Bash-portability review: microsoft#2632 (comment)
- Interacting pull request: microsoft#2635

## Rationale
A package-scoped overload preserves the existing public JVM API while letting runtime callers apply the active Spark resolver semantics. Normalizing only a unique case-insensitive schema match avoids inventing precedence when case-colliding columns exist. Explicit selection state in the replay loop is portable across supported Bash versions and clearer than inspecting the last array element.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 16, 2026 11:39
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

The suppressed Copilot observation in review 4945931887 is also addressed by 0564a2b: ambiguous metadata guidance now recommends explicit scoredLabelsCol/scoresCol selection when labelCol and evaluationMetric are insufficient, or removal of stale metadata.

@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

Rana Singh (ranadeepsingh) pushed a commit to ranadeepsingh/SynapseML that referenced this pull request Aug 16, 2026
## Summary
Resolve configured label columns using Spark case-sensitivity semantics across model and per-instance statistics, use the default Spark session when transformSchema has no active session, improve ambiguous metadata guidance, and remove non-portable Bash negative array indexing from release replay.

## Prompting Intent
Address every final Copilot review comment on PR microsoft#2632 while preserving deterministic metadata selection, schema propagation, compatibility, and Spark 4.1 replay behavior.

## Linked Sources
- Pull request: microsoft#2632
- GitHub issue: microsoft#1697
- Case-resolution review: microsoft#2632 (comment)
- Bash-portability review: microsoft#2632 (comment)
- Default-session review: microsoft#2632 (comment)
- Interacting pull request: microsoft#2635

## Rationale
A package-scoped overload preserves the existing public JVM API while letting runtime callers apply Spark resolver semantics. Normalizing only a unique case-insensitive schema match avoids inventing precedence when case-colliding columns exist. transformSchema prefers the active session but falls back to the default session so its resolver matches runtime configuration whenever Spark context is available. Explicit replay selection state is portable across supported Bash versions and clearer than inspecting the last array element.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ranadeepsingh
Rana Singh (ranadeepsingh) force-pushed the copilot/issue-1697-metric-metadata branch from 0564a2b to 49dcd37 Compare August 16, 2026 13:00
Copilot AI review requested due to automatic review settings August 16, 2026 13:00
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (1)

pipeline.yaml:1219

  • Same as above: LATER_PARENT=$(git rev-parse ...) runs under set -e and can terminate the release-compat job with an unstructured git error if a later prerequisite is invalid. Wrap this rev-parse in an if ! ...; then with a ##vso[task.logissue type=error] message so failures are actionable and consistent.
                  LATER_PREREQUISITE="${CONFIGURED_PREREQUISITES[$later_index]}"
                  LATER_PARENT=$(git rev-parse "$LATER_PREREQUISITE^1")
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread pipeline.yaml Outdated
## Summary
Resolve configured labels using Spark case-sensitivity semantics in metadata-backed and fully explicit evaluation, use the default Spark session when transformSchema has no active session, improve ambiguity guidance, and harden release replay portability and dependent-prerequisite diagnostics.

## Prompting Intent
Address every Copilot review comment on PR microsoft#2632 while preserving deterministic metadata selection, schema propagation, API compatibility, and Spark 4.1 replay behavior with end-to-end negative coverage.

## Linked Sources
- Pull request: microsoft#2632
- GitHub issue: microsoft#1697
- Case-resolution review: microsoft#2632 (comment)
- Bash-portability review: microsoft#2632 (comment)
- Default-session review: microsoft#2632 (comment)
- Explicit-schema review: microsoft#2632 (comment)
- Replay-diagnostics review: microsoft#2632 (comment)
- Interacting pull request: microsoft#2635

## Rationale
A package-scoped resolver preserves the existing public API while applying identical unique case-insensitive matching in metadata-backed and explicit paths. transformSchema prefers the active session and falls back to the default session so schema inference follows runtime configuration whenever Spark context exists. Explicit replay selection avoids Bash negative-index compatibility issues, and guarded parent resolution yields deterministic Azure errors for root or invalid dependent prerequisites; parameterized end-to-end tests exercise both dependent scans.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ranadeepsingh
Rana Singh (ranadeepsingh) force-pushed the copilot/issue-1697-metric-metadata branch from 49dcd37 to f0c7dab Compare August 16, 2026 14:22
Copilot AI review requested due to automatic review settings August 16, 2026 14:22
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@BrendanWalsh
Brendan Walsh (BrendanWalsh) merged commit 704fb34 into microsoft:master Aug 17, 2026
77 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] ComputeModelStatistics doesn't work on multiple trainings, java.lang.NullPointerException

4 participants