Skip to content

[.NET] Consume TCGC LRO status metadata and operation ID - #12563

Draft
iscai-msft wants to merge 1 commit into
microsoft:mainfrom
iscai-msft:dotnet-shared-lro-metadata
Draft

iscai-msft wants to merge 1 commit into
microsoft:mainfrom
iscai-msft:dotnet-shared-lro-metadata

Conversation

@iscai-msft

@iscai-msft iscai-msft commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Summary

Shared prerequisite for the coordinated Azure .NET generator change. Preserve TCGC statusMetadata, typed propertySegments, and ordered operationId selections through the shared TypeScript code model and strongly typed C# input conversion. The Azure companion owns idiomatic generated operation/poller access and runtime integration scenarios; this PR does not add Azure-specific poller APIs or remove SDK customizations.

Feature contracts: Azure/typespec-azure#5677, Azure/typespec-azure#5927, Azure/typespec-azure#5782.

Part of Azure/typespec-azure#5996

TCGC is already pinned to 0.74.0, with the stable TypeSpec 1.18.0 / 0.88.0 dependency family, by #12552; no redundant dependency bump is needed here. This does not consume result-default changes from Azure/typespec-azure#5837 or endpoint/OAuth configurations from Azure/typespec-azure#5710.

Shared consumption contract

  • InputLongRunningServiceMetadata.StatusMetadata: ordered InputLroStatusMetadata entries with Property and typed PropertySegments, rooted at pollingInfo.responseModel. Client/wire names, optionality, selected output type graphs, and shared property references survive serialization.
  • InputLongRunningServiceMetadata.OperationId: ordered InputLroOperationIdPathMetadata then InputLroOperationIdPropertyMetadata when both sources are selected. Property entries preserve Property and typed PropertySegments. Path entries preserve Source.Location, Source.Property, PathParameter, and PollingPath (the modeled monitor route), so the selected ID need not be the last URI segment.
  • Both collections are empty for legacy input with no selections; existing constructors and final-result metadata remain compatible. Unknown future metadata properties are skipped rather than leaving the reader stuck.
  • Consumers must use matching shared emitter and Microsoft.TypeSpec.Generator.Input builds. Polling still uses the complete polling URL; extracted IDs do not replace it. The Azure companion must implement latest-response refresh/absence, initial monitor values, failure/cancellation access, URI fallback, and post-rehydration behavior.

Validation and boundary

Passed locally:

  • Full npm run build, including API extraction.
  • Full emitter suite: 431 passed, 2 skipped. New regressions cover direct/inherited order, renamed JSON/client properties, optional and model-valued selections, URI-only/body-only/both/absent ID selections, a non-final ID URI segment, and serialized reference preservation.
  • Full generator suite: 7,284 passed, 961 skipped: input 338, core 3,316, ClientModel 2,779, local runtime 836, existing shared Spector 15 passed / 961 skipped. Input regressions exercise both lro and lropaging via TypeSpecSerialization, typed multi-segment paths, shared/forward references, ordered ID sources, invalid shapes, and legacy/unknown fields.
  • Full eng/scripts/Generate.ps1: completed successfully with no tracked generated-source changes, preserving existing public APIs.
  • Repository and package formatting, repository oxlint on the emitter, C# formatting, git diff --check, and npm run cop (cop checks passed.).

The package's existing npm run lint script invokes ESLint without a flat config and fails; the repository-standard oxlint check passes. This PR does not claim execution of the new Azure LRO metadata/operation-ID Spector scenarios or their public-accessor lifecycle assertions: those belong to the Azure companion. Existing shared Spector stubs being skipped is not evidence that the new Azure scenarios pass.

Customization database handoff

The verified customization read model on iscai-msft/typespec-azure branch sdk-customization-metrics at commit a3b68e6b480649a754aa6b64455d83b53527d113 contains 54 accepted .NET LRO findings across 24 SDK packages: 1 operation-ID facet covered and 53 findings not covered. This audit is copied from the Azure companion PR.

Coverage is prospective and depends on the Azure companion: this PR only transports metadata; it does not itself generate consumer-facing poller APIs or runtime behavior, and no handwritten SDK customization is removed. Covered refers only to the ID or auxiliary metadata facet after emitter support ships. Custom terminal states, result projection, and paged LRO results remain not covered. Translation has an ID/metadata facet but is not counted because custom terminal states and paged results remain unsupported. ConfidentialLedger's initial custom header/body selection is not covered by a linked monitor URI/modeled monitor-body selection. Related findings are grouped; each 12-character identifier is a distinct finding.

SDK package handwritten code (commit-pinned GitHub link with line range) what generated code now provides TypeSpec annotation the spec needs (@lroStatusMetadata / @lroOperationId)
Azure.AI.Discovery Replace synchronous delete with a delete-until-gone operation 1e35c0826841: L29-L32 L108-L130
Replace asynchronous delete with delete-until-resource-404 polling 7e5f04037499: L29-L32 L139-L161
Implement a resource-GET delete operation that completes only on HTTP 404 9b345f219483: L12-L60 L163-L177
Not covered: Polling a resource until HTTP 404 and exposing its resource name as ID are custom completion/resource-ID behavior. Not applicable.
Azure.AI.Discovery Implement resource-provisioning completion with explicit state precedence and synchronous shortcut 761263e71004: L13-L101 L163-L207
Replace synchronous create/update with the resource-provisioning operation 80415c0f53f1: L29-L66
Replace asynchronous create/update with a provisioning-state operation e77f38e398d4: L29-L32 L76-L99
Not covered: Provisioning-state precedence, original-resource polling, and no-location completion alter the polling protocol. Not applicable.
Azure.AI.DocumentIntelligence Custom Operation wrapper exposing operation Id caba7c0e715e: L250-L278 Covered: The operation-location URI ID facet can be exposed by the generated operation. The existing wrapper also reads the initial response body when the header is absent; that fallback is not implied unless the body is the modeled status monitor. @lroOperationId on the linked monitor operation's ID path parameter; a string-like monitor response property can be annotated separately.
Azure.AI.Language.Conversations Typed asynchronous analysis waits and unwraps operation result 4a79206e885d: L53-L63
Typed synchronous analysis waits and unwraps operation result bdee245bb3cc: L33-L43
Not covered: Waiting and converting raw responses to typed results are result-adapter behavior, not poller metadata. Not applicable.
Azure.AI.Language.Conversations Asynchronous operation-location protocol wrapper 83f5e4b017ad: L102-L119
Synchronous operation-location protocol wrapper c1a7282128a0: L74-L91
Not covered: These protocol wrappers choose operation-location polling but do not expose an operation ID or auxiliary status metadata. Not applicable.
Azure.AI.Language.Text Asynchronous wait-to-completion wrapper and typed raw-result conversion 67a652b2bfcf: L80-L104
Synchronous wait-to-completion wrapper and typed raw-result conversion da67d8c00d59: L47-L71
Not covered: Waiting and converting raw responses to typed results are result-adapter behavior, not poller metadata. Not applicable.
Azure.AI.Language.Text.Authoring scoped-cancellation-token-operation-adapter 2b041b9f79a6: L229-L252
scoped-typed-delete-resources-operation-adapter 3725999aaec8: L194-L224
scoped-typed-deploy-operation-adapter b6d9242e95ad: L158-L188
scoped-operation-location-lro-entry-point f1a69ce514f1: L120-L150 L350-L368
scoped-export-delete-operation-adapter f42751f00c28: L155-L178
Not covered: Scoped request, context, and typed entry-point adapters are not generated by these metadata annotations. Not applicable.
Azure.AI.Translation.Document operation-location-wrapper 6eb9ca22a185: L103-L121 L163-L181 L224-L242
async-operation-location-wrapper cc29acaaa040: L133-L151 L193-L211 L255-L273
Not covered: The custom translation operation has ID and auxiliary counter facets, including URI ID extraction, but its custom terminal behavior and paged LRO results are not covered, so these wrapper findings are not counted. For the supported facet only, @lroOperationId on the linked monitor ID path parameter and @lroStatusMetadata on auxiliary counter/timestamp properties.
Azure.Developer.DevCenter Model-name-derived typed environment operation wrappers dccfb84ae565: L14-L16 L35-L45 L55-L65
Model-name-derived typed Dev Box operation wrappers f58f012832f3: L14-L16 L35-L46 L56-L67
Not covered: Deriving resource names, adapting inputs, and converting typed operation results are unrelated to metadata exposure. Not applicable.
Azure.Developer.LoadTesting Test-run creation wrapped as LRO 527c09fd508a: L55-L83 L96-L124
Profile-run creation wrapped as LRO bca84c3409f3: L136-L164 L176-L204
File upload wrapped as validation LRO f42c06a4b7d1: L55-L84 L98-L127
Not covered: These wrappers construct resource-specific operations and control completion waits and polling intervals. Not applicable.
Azure.Developer.LoadTesting File upload operation ID assembled from resource keys b10456beae2d: L84-L90 Not covered: The ID is assembled from resource keys, not obtained from a server-issued monitor URI or monitor response property. Not applicable.
Azure.Developer.LoadTesting File-validation completion from response JSON b16e23a0abeb: L25-L31 L39-L68 L90-L97 L162-L191 Not covered: The validation-specific terminal states and completion logic are not provided. Not applicable.
Azure.Developer.LoadTesting Poll uploaded file resource for status bbb82ef8fb46: L120-L131 L141-L160 Not covered: Polling the uploaded resource and custom failure handling are protocol behavior. Not applicable.
Azure.ResourceManager.AppContainers Completed certificate update as response a7736398ac7d: L40-L45 L71-L76 Not covered: Converting a completed operation result into a resource response is result projection. Not applicable.
Azure.ResourceManager.Authorization Typed DELETE operation wrapper 8249629b516f: L57-L85 L110-L137 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.ContainerInstance Suppressed Delete startup with typed operation and conditional wait c65c878e4a27: L15-L17 L24-L55 L62-L93 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.ElasticSan Typed restore operation using Location final state 7103b7d53961: L177-L200 L221-L244 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.EventGrid Bound reconcile starts a data operation and adapts its result type cd25fffe5b92: L125-L161 L167-L203 Not covered: Operation-result deserialization and domain-resource conversion are result projection. Not applicable.
Azure.ResourceManager.GuestConfiguration Replacement delete methods construct typed rehydratable operations d25344c2b750: L85-L105 L117-L137 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.HybridConnectivity Typed operation-result deserialization efff7372a29a: L19-L19 L29-L44 Not covered: Operation-result deserialization and domain-resource conversion are result projection. Not applicable.
Azure.ResourceManager.IotHub Suppressed delete signatures are replaced with a typed-resource operation 2880efeaa513: L27-L29 L174-L204 L228-L258 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.KeyVault Typed delete operation replacement a76f093fae14: L16-L18 L179-L209 L233-L263 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.NewRelicObservability Completed-operation result rewrapped as a resource response 7703ecaa0495: L50-L54 L80-L84 Not covered: Converting a completed operation result into a resource response is result projection. Not applicable.
Azure.ResourceManager.Resources.Deployments Scope-dispatched What-If LRO start and conditional wait 69f899e5876b: L359-L386 L388-L403 Not covered: Scope-dispatched request construction and final-state routing are custom operation behavior. Not applicable.
Azure.ResourceManager.Search Delete operation wrapping a returned resource 6ecf95c151ce: L19-L22 L50-L77 L105-L132 Not covered: Typed ARM operations, final-state selection, response conversion, and rehydration are not metadata exposure. Not applicable.
Azure.ResourceManager.TrafficManager typed-delete-initiation-to-nongeneric-operation 4f7283c1a167: L228-L255 L260-L287
typed-create-initiation-and-operation-result-adapter 919f88605208: L90-L122 L143-L175
Not covered: Typed operation construction, result adaptation, and rehydration are unrelated to the two annotations. Not applicable.
Azure.Security.ConfidentialLedger Queued-write operation ID extraction 38d8586e5736: L366-L383 Not covered: The ID comes directly from a custom initial-response header or initial body, not a linked monitor URI or modeled monitor response property. Not applicable.
Azure.Security.ConfidentialLedger Commit-aware operation creation and waiting e0d386222855: L21-L22 L208-L277 L298-L364 Not covered: Commit-aware request/response orchestration and waiting are not provided. Not applicable.
Azure.Security.KeyVault.Certificates Wrap generated create responses in a public certificate operation 7f423911a9dd: L159-L204 L221-L266 Not covered: Wrapping typed certificate responses and operation construction is not selected status metadata. Not applicable.
Azure.Security.KeyVault.Secrets Initial deleted value available before polling completion 4f8b65530974: L54-L54 L67-L67
Initial recovery properties available before completion 8c1e9854d701: L44-L44 L57-L57
Not covered: Making the initial result value available before completion changes result semantics, not auxiliary metadata. Not applicable.
Azure.Security.KeyVault.Secrets Two-second default recovery polling interval 52c412463499: L18-L18 L71-L72
Two-second default asynchronous wait e7600b4a62de: L18-L18 L81-L82
Not covered: A two-second polling interval is a wait configuration, not metadata. Not applicable.
Azure.Security.KeyVault.Secrets Recovered-resource status polling afa7814f8490: L78-L91
Deleted-resource status polling dcafca69d828: L88-L104
Not covered: Treating 200/403 as complete and 404 as pending is custom resource-status polling. Not applicable.
Azure.Security.KeyVault.Secrets Delete operation completes immediately without recovery ID ba579de21cda: L24-L39 Not covered: Immediate completion when a recovery ID is absent is a custom polling rule. Not applicable.
Azure.Security.KeyVault.Secrets Recovery operation exposes secret URI ID c054c2859205: L35-L35
Secret URI exposed as operation ID dd95ae7f6bf8: L45-L45
Not covered: The operation exposes a secret resource URI, not a server-issued monitor operation ID. Not applicable.

Draft follow-ups

  • Publish compatible shared emitter and generator packages for consumption by the Azure companion.
  • The companion must consume the corrected Spector fixture from Azure/typespec-azure#6070 and rerun its six new lifecycle scenarios; its latest run passed five and failed one due to the fixture route.

Do not merge independently of the companion's compatible shared-package consumption.

Changeset

No .chronus changeset is included, by user decision. @typespec/http-client-csharp is outside the pnpm workspace and is not tracked in .chronus/config.yaml, so chronus verify rejects a C# entry with invalid-package-name. A C# changeset was removed for the same reason in e68c1a4eb.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Nov 12, 2026
@pkg-pr-new

pkg-pr-new Bot commented Nov 12, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@12563

commit: c531ef5

@github-actions

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

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

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant