Skip to content

feat: add opt-in recovery for AIPrompt results - #2813

Draft
Rana Singh (ranadeepsingh) wants to merge 12 commits into
microsoft:masterfrom
ranadeepsingh:feat/aiprompt-recovery-20261105
Draft

Rana Singh (ranadeepsingh) wants to merge 12 commits into
microsoft:masterfrom
ranadeepsingh:feat/aiprompt-recovery-20261105

Conversation

@ranadeepsingh

Copy link
Copy Markdown
Collaborator

Repeated Spark actions and interrupted inference can repeat paid model requests while leaving users without saved outcomes. This draft adds opt-in Delta input/result snapshots and explicit recovery of uncommitted rows, without promising exactly-once external requests.

Draft; not runtime-qualified or merge-ready. Compilation, scoped style/static checks and integrated code generation passed. Recovery behavior is not yet qualified.

Related Issues/PRs

Tracks #2800, the optional recovery portion of #2759. Keep the umbrella open while separately tracked work remains incomplete. Live Decisions qualification remains #2760.

Stacked dependency: #2811 supplies the focused native API. This branch includes that PR and its prerequisite fixes so it can build before they land; the recovery-specific delta is 42 files. Merge the prerequisites and native API first, then rebase this draft to remove their commits.

The separate GlobalParams concurrency repair in #2806 is inherited, not duplicated. Further Python stub repairs belong in #2810 rather than the recovery implementation.

What changes are proposed in this pull request?

  • Add optional outputPath and bounded outputBatchSize execution. Ordinary inference remains lazy without requiring Delta.
  • Persist an immutable input snapshot and versioned results ledger, preserving duplicate rows, supported schema metadata and vectors.
  • Add resume, loadOutput, getOutputStatus and exact-token administrative owner release, plus Python methods. Committed errors are terminal outcomes, not automatically retried requests.
  • Validate request/build/runtime identity and self-contained inputs. Keep credentials out of the manifest; callers must protect persisted data and rebind supported credentials.
  • Retain interruption, driver-death and ownership-race regressions, including interruptible Windows lock acquisition.
  • Reuse core value handling and add a separate recovery guide/notebook. The canonical AIPrompt.ipynb stays unchanged.

An uncommitted batch, Spark retry or ambiguous provider response can still repeat paid requests. Status counts do not prove task quiescence. Administrative release requires confirming previous work has stopped; there is no automatic lease expiry or force takeover.

Excluded: optional response-byte limits, legacy OpenAIPrompt reader interoperability, live Decisions qualification, tool-execution loops, dependency-pin/CI/release changes, and unrelated legacy repairs.

How is this patch tested?

  • I have written tests (not required for typo or doc fix) and confirmed the proposed feature/bug-fix/change works.

The extracted 42-file recovery delta was checked using JDK 11, with build outputs and caches isolated from the main checkout. These are the SBT tasks passed to that launcher:

Command/check Result
sbt cognitive/compile cognitive/Test/compile Passed on the extracted revision and after integrating the native API follow-ups.
sbt core/scalastyle core/Test/scalastyle cognitive/scalastyle cognitive/Test/scalastyle Passed on the extracted and integrated revisions, zero style errors/warnings.
sbt core/codegen cognitive/codegen Passed after integrating the native API follow-ups.
python -m black --check cognitive\src\test\python\synapsemltest\services\test_AIPromptRecovery.py cognitive\src\test\python\synapsemltest\services\aiprompt_fabric_recovery_e2e.py Passed with Black 22.3.0; both files unchanged.
node --check website\sidebars.js Passed.
git diff --check Passed.
Local extraction verifier Passed: Python/notebook syntax, disabled sample flags, exact file manifest, preservation of the original snapshot, and unchanged canonical notebook.

The current native-API follow-ups were fast-forwarded into the recovery branch without changing any of the 42 recovery delta files. Integrated compilation, styles and code generation passed with the final stub body-string repair. The final fast-forward also inherits the formatting-only canonical notebook update and corrected coverage-upload count from the native PR.

Not run: runtime Scala tests; both ownership races in a fresh JVM; cancellation and driver-death tests (process termination requires explicit opt-in); codec/schema/identity execution; generated/installed Python and wheel tests; lazy-without-Delta runtime checks; managed-runtime E2E; website rendering; required CI and port validation. These are gates, not passes. Run them on the exact final integrated artifacts before making support claims.

Passing native API and prerequisite tests do not qualify recovery. Retain the race and cancellation tests rather than weakening them.

Managed-runtime limit: interruption within one Spark application does not qualify stopping and restarting that application. Application-restart recovery remains unqualified; bundled Delta alone is not compatibility evidence.

Does this PR change any dependencies?

  • No. You can skip this section.
  • Yes. Make sure the dependencies are resolved correctly, and list changes here.

No dependency manifests or pins changed. Durable execution requires a caller-configured compatible Delta runtime. No Delta test dependency was added; runtime validation remains pending.

Does this PR add a new feature? If so, have you added samples on website?

  • No. You can skip this section.
  • Yes. Make sure you have added samples following below steps.

Added Durable AI results.md and Quickstart - Durable AI results.ipynb, linked from the overview/sidebar. Notebook outputs are cleared; RUN_NEW, RUN_READ and RUN_RESUME default to false. Syntax passed; website rendering and recovery-notebook execution remain unvalidated.

  1. Find the corresponding markdown file for your new feature in website/docs/documentation folder.
    Make sure you choose the correct class estimators/transformers and namespace.
  2. Follow the pattern in markdown file and add another section for your new API, including pyspark, scala (and .NET potentially) samples.
  3. Make sure the DocTable points to correct API link.
  4. Navigate to website folder, and run npm start to make sure the website renders correctly.
  5. Don't forget to add <!--pytest-codeblocks:cont--> before each python code blocks to enable auto-tests for python samples.
  6. Make sure the WebsiteSamplesTests job pass in the pipeline.

## Summary
Protect global parameter registration, value updates, lookup and reset with one
shared monitor. Add bounded child-JVM regressions for concurrent stage use,
including the existing present-null and reset semantics.

## Prompting Intent
Keep the AIPrompt feature focused and publish independently demonstrated
pre-existing defects as separate fixes. Reproduce the concurrency failure on
baseline without allowing a corrupted map to hang the test runner.

## Linked Sources
- Bug: microsoft#2804
- Scope: microsoft#2759
- Deferred recovery: microsoft#2800

## Rationale
A shared monitor makes the two-map lookup consistent and preserves existing
signatures and Scala Map null/Option behavior. Replacing only one map or using
a null-rejecting concurrent collection would not preserve that contract.
Baseline concurrency probes failed; the fixed probes and existing global
parameter tests passed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Pass the MLReader or MLWriter session into complex parameter serialization
and deserialization. Retain the existing helper overloads and stored format.
Cover writer selection and both directions of reader deserialization policy.

## Prompting Intent
Separate unrelated persistence repairs from the native AIPrompt feature.
Prove that a caller-selected Spark session governs complex payload handling
rather than inheriting an unrelated active session's configuration.

## Linked Sources
- Bug: microsoft#2803
- Scope: microsoft#2759

## Rationale
Threading the already assigned session through overloads fixes the actual
boundary without changing global Spark state, serialized parameter shapes or
unsafe-deserialization defaults. The three regressions failed on baseline and
passed with the existing serialization and UDF persistence suites.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Resolve the two generator review findings by sharing scope-aware method
extraction between stub generation and ServiceParam alias validation.
Preserve binding decorators across comments, blank lines and stacked decorators.

## Prompting Intent
Keep AIPrompt focused, isolate independent defects into their own PRs, and
resolve review findings with regression evidence rather than unrelated changes.

## Linked Sources
- microsoft#2805
- microsoft#2810
- microsoft#2810 (comment)
- microsoft#2810 (comment)
- microsoft#2759

## Rationale
Keep the existing synchronous single-line method-signature grammar while
tracking enclosing function/class scopes and complete decorator blocks.
Extract the helper and fixture object to respect the repository's file-length
limit without changing fixture JVM names or adding Python parser dependencies.
Three regressions fail on the preceding PR implementation, and two multiline
header regressions fail before the scope-continuation repair. All 26 codegen
tests and both Scala style gates pass in the isolated and integration trees.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Preserve actual thread and Spark-task cancellation through attachment reads
and prompt message construction. Keep ordinary timeout and IO failures as
sanitized row diagnostics. Cover both legacy generative APIs through public
transform actions and retain existing request and persistence cases.

## Prompting Intent
Repair the independently reproduced legacy cancellation defect in its own PR,
without bundling native AIPrompt adapters, bounded attachment features or
optional recovery machinery.

## Linked Sources
- Bug: microsoft#2801
- Scope: microsoft#2759

## Rationale
Cancellation is control flow and must unwind inference rather than become a
normal content-row error. Recognize actual task/thread interruption while
preserving sanitized behavior for unrelated failures. All three new regression
cases failed on baseline; the complete 25-test legacy multimodal suite passed
with the fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Close responses in a finally block when converting HTTP response data.
Add a regression that propagates the conversion failure while checking that
the response is closed exactly once.

## Prompting Intent
Publish the independent response-resource cleanup defect separately from
AIPrompt's new opt-in transport behavior. Keep the fix narrow and prove the
baseline failure directly.

## Linked Sources
- Bug: microsoft#2802
- Scope: microsoft#2759

## Rationale
The existing success-only close skipped cleanup when body conversion threw.
A try/finally fixes that path without changing retry accounting, adding response
limits or depending on the new native buffering implementation. The regression
failed on baseline and passed with the existing response inspection tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Add AIPrompt on the existing OpenAIPrompt interface for explicit chat,
Responses, embeddings and native decision-model APIs. Preserve request
options, typed results, errors and raw responses through Scala and generated
Python, copy, persistence and pipelines. Add the AIPrompt notebook and guide.

## Prompting Intent
Keep the contribution focused on AIPrompt and small native specializations.
Separate independent legacy defects and optional Delta recovery into their
own issues and PRs. Exercise supported notebook examples on packaged
artifacts, but leave OpenAIDecisions examples commented because Azure
OpenAI/Foundry does not support that API.

## Linked Sources
- Native inference proposal: microsoft#2759
- Deferred recovery: microsoft#2800
- Deferred live Decisions qualification: microsoft#2760
- Global parameter prerequisite: microsoft#2806
- Attachment cancellation prerequisite: microsoft#2807
- Response cleanup prerequisite: microsoft#2808
- Assigned-session prerequisite: microsoft#2809
- Python stub prerequisite: microsoft#2810
- Existing tutorial: docs/Explore Algorithms/OpenAI/OpenAI.ipynb

## Rationale
Reuse existing authentication and HTTP infrastructure rather than add a
second inference transport. Keep public behavior in Scala and generate
Python conveniences without changing legacy public JVM signatures or
serialized parameter shapes. Explicit API selection and lossless JSON avoid
silent option loss; bounded cancellation handles interrupted Spark work.
Keep ordinary inference lazy and replayable, without Delta, an automatic
tool loop, response-size configuration or an exactly-once claim.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
Summary
- Preserve quote, escape, delimiter and continuation state across multiline
  headers and decorators in the shared Python method extractor.
- Recognize binding decorators with trailing comments and retain their binding
  across nonbinding multiline decorators.
- Cover six additional regressions with Python syntax-checked fixtures.

Prompting Intent
- Keep the AIPrompt contribution focused and repair independent generator
  regressions in their own prerequisite pull request.

Linked Sources
- microsoft#2805
- microsoft#2810
- microsoft#2759

Rationale
- Punctuation inside strings and comments must not change method scope or
  accidentally discard a pending static/class binding.
- All six new regressions fail on the preceding extractor. All 32 generator
  tests, compilation and both style gates pass with this repair.
- Only the private extractor and its existing fixture/suite files change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
Summary
- Apply the pinned Black formatter to the AIPrompt regression suite and its
  Fabric validation helper.

Prompting Intent
- Keep the focused AIPrompt pull request limited to required feature work
  and repairs to its own validation gates.

Linked Sources
- microsoft#2811
- https://github.com/microsoft/SynapseML/actions/runs/42014432464

Rationale
- The Python style gate identified formatting in two new test files.
- The changes preserve both files' Python ASTs, and the repository's
  tracked Python files pass Black 22.3.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Keep the existing lexical state current while skipping nested function and
class bodies. Triple-quoted body strings must not create false public accessor
collisions or hide a real accessor defined after the skipped scope.

## Prompting Intent
Resolve the current-head review findings for the independent Python stub
scope fix and integrate the verified repair into the focused AIPrompt work,
without expanding the native feature or optional recovery scope.

## Linked Sources
- microsoft#2805
- microsoft#2810 (review)
- microsoft#2811 (comment)
- microsoft#2759

## Rationale
Advance the existing expression scanner instead of adding another parser.
Four syntax-valid function/class regressions failed before the repair.
All 36 PyCodegenSuite cases, main/test compilation and both style gates pass
in the isolated prerequisite and integrated native-feature worktrees.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
Account for the additional AI test lane in Codecov's expected upload count
and apply the pinned notebook formatter to the new AIPrompt tutorial.

## Prompting Intent
Repair the deterministic checks introduced by the focused AIPrompt change
without changing dependency pins, workflows, release tooling or unrelated
notebooks, and preserve the already-executed tutorial behavior.

## Linked Sources
- microsoft#2759
- microsoft#2811

## Rationale
The authorized AI matrix lane raises expected uploads from 54 to 55.
Keep the existing coverage-count assertion unchanged and fix its configuration.
Black 22.3.0 with Jupyter support changes formatting only: all 18 code-cell
ASTs, metadata and markdown remain identical, outputs stay cleared and
OpenAIDecisions remains commented. The full CI Black command and the targeted
coverage-upload selection test pass locally.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
## Summary
- Extract the optional Delta input snapshot, result ledger and explicit
  recovery API from the original combined AIPrompt work.
- Keep ordinary inference lazy, reuse the native value codec, and retain
  ownership, cancellation and interrupted-driver regression coverage.
- Add a separate disabled-by-default recovery notebook and usage guide.

## Prompting Intent
- Keep the native AIPrompt pull request focused and move storage/recovery
  work into a separate explicitly unqualified draft.

## Linked Sources
- microsoft#2759
- microsoft#2800
- microsoft#2811

## Rationale
- Recovery changes storage, ownership and replay behavior and should not
  expand or block review of the focused native API.
- Retain the original recovery implementation and test intent without
  adding response limits or legacy-reader interoperability.
- Compilation and static/style checks are not runtime qualification.
  Ownership races, cancellation, process restart, matching installed
  artifacts, managed runtimes and current-head CI remain required.
- Uncommitted or ambiguous provider calls can still be repeated; this
  feature does not promise exactly-once model execution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
@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

github-actions Bot commented Nov 5, 2026

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.

@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

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

## Summary
Track multiline strings and expressions in ordinary class statements so
declaration-like string content cannot hide subsequent methods or bypass
generated service-parameter accessor collision checks.

## Prompting Intent
Keep AIPrompt focused, fix regressions, and publish unrelated fixes separately.
Resolve current-head review findings without expanding the feature scope.

## Linked Sources
- Stub fix: microsoft#2810
- Stub issue: microsoft#2805
- Review: microsoft#2810 (review)
- Duplicate review: microsoft#2811 (review)

## Rationale
Reuse the existing lexical state for all class statements instead of adding
another parsing path. Four public code-generation regressions fail before
the repair and pass afterward, covering direct class statements and control
blocks. All 40 PyCodegenSuite cases, core compile/test compile, and both
Scala style checks pass. Share the existing alias-conflict assertions to
keep the suite within its file-length limit without weakening coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ba39157-c8dd-4adb-90e0-ff963a1e6733
@ranadeepsingh

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

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

This branch has not been deployed

No deployments
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.

1 participant