Skip to content

[Swagger Linter Migration] LroExtension + XMSLongRunningOperationProperty -> lro-missing-polling-metadata - #5652

Open
Yuchao Yan (msyyc) wants to merge 13 commits into
mainfrom
promote-lintdiff-lro-extension
Open

Yuchao Yan (msyyc) wants to merge 13 commits into
mainfrom
promote-lintdiff-lro-extension

Conversation

@msyyc

@msyyc Yuchao Yan (msyyc) commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Observable acceptance follow-up (October 21, 2026)

Published in 09b7f5127. This follow-up implements ID28's callback cleanup and retains the evidence-backed ID27 interaction regression. It supersedes the earlier skipped-ID27/28 and callback-inspection statements; historical results below remain historical.

  • Native resource PUT/PATCH/DELETE positives now use toBeValid() without HTTP response/header inspection. Matching public LroHeaders = PlainLocationHeaders PATCH/DELETE customizations warn at the authored operation; existing independent verb/status/header and cardinality cases remain.
  • A one-time inversion of metadata acceptance made the exact three native positives emit this ARM warning, at createOrUpdate, update and remove. The mutation was restored byte-for-byte; no production code change is published.
  • Retained the single registered original-uri interaction case. With only this ARM rule enabled, its resolver can emit Core diagnostics. After rebuilding the registered entry, a duplicate-resolver mutation failed with two no-operation-at-original-uri diagnostics instead of one. The restored registered case passes.
  • Final local validation: 40 canonical rule tests + 1 public-entry isolation test passed; ARM package build/production typecheck/library lint, focused changed-test/shared-tester typecheck, root pnpm format, root pnpm lint, and diff hygiene passed. Production source and built entry were restored before final validation. This is not a claim that the broader test TypeScript project or CI is green.
  • Validation notes: an initial plain-header PUT negative produced no warning and was not retained as an invalid fixture. The first isolated registered probe timed out in the stock setup hook; a source-only probe did not exercise the built registered entry. The conclusive probe rebuilt that entry. No timeouts, cache settings, compiler pin, manifests, lockfile, activation or public examples changed.

Summary

Consolidate LroExtension and XMSLongRunningOperationProperty into the single public ARM rule @azure-tools/typespec-azure-resource-manager/lro-missing-polling-metadata. This PR absorbs the official-destination policy and unique regression coverage from #5709 rather than adding a second rule with the same name.

Published in 3ca178be4, following the combined-migration presentation in #5556, #5294 and #5423 and the review request on #5709.

Please continue review of both migrated policies here. #5709 is marked superseded by this combined proposal but remains open, with its branch and review history retained. This consolidation does not resolve existing review threads, claim reviewer agreement, or establish fresh CI approval.

Combined behavior and legacy-rule mapping

Swagger validator Combined native coverage
LroExtension All PATCH operations, and POST operations marked as ARM provider/collection actions, require native polling metadata when they have an explicit numeric 202 response, even without a polling header. This remains partial native coverage of the broader Swagger selector.
XMSLongRunningOperationProperty PUT/PATCH/POST/DELETE operations require native polling metadata when an explicit numeric 200, 201, 202 or 204 response contains a case-insensitive Location or Azure-AsyncOperation header.

The triggers are related but not interchangeable. A headerless PATCH 202 exercises only the first; PUT 201 with Location exercises only the second; a marked provider POST 202 with Location exercises both.

  • One native callback and one warning per operation. The linter's operation listener resolves HTTP metadata per concrete endpoint within an explicit service namespace (including nested namespaces), without a per-service walk, visited-operation bookkeeping, or no-service global fallback. Either trigger selects the operation for one getLroMetadata call. The registered overlapping-service regression retains exactly one Core resolver-side-effect diagnostic and zero ARM warnings. Matching both triggers or several headers/statuses does not duplicate the ARM warning. Different operations sharing response properties remain independent.
  • One authored-operation target. The combined diagnostic uses [Swagger Linter Migration] LroExtension + XMSLongRunningOperationProperty -> lro-missing-polling-metadata #5652's operation targeting. This intentionally replaces [Swagger Linter Migration][Superseded by #5652] XMSLongRunningOperationProperty -> lro-missing-polling-metadata #5709's proposed first-header target and header-property suppression location; success-code/header ordering no longer chooses the diagnostic location. Apply approved exceptions to the concrete operation.
  • Native semantics, not output overrides. Only supported polling metadata satisfies the rule. An output-only x-ms-long-running-operation: true does not. GET/polling GET and HEAD remain excluded; Operation-Location and Retry-After do not trigger the ARM header policy. The existing explicit-numeric-status behavior is retained; broader ranges do not qualify.
  • Audience stays ARM. Concrete HTTP operations are checked only within explicitly declared services, including nested namespaces and overlapping services. Operations outside services and no-service programs remain excluded. Neither policy requires provider-namespace metadata; the development runner's mixed-audience isolation guards remain absent from the official copy.
  • Existing rule ownership is retained. ARM response-code rules and lro-location-header still own their status-set/header-presence policies; Core's Operation-Location polling-link rule is not replaced. Registered-resource POST/PUT/DELETE operations can now additionally receive this rule's header-triggered warning, as already proposed by [Swagger Linter Migration][Superseded by #5652] XMSLongRunningOperationProperty -> lro-missing-polling-metadata #5709.
  • Enablement is not silently expanded to a second rule. There remains one false entry in the central Azure resource-manager ruleset. The ARM library's compiler-generated all includes registered rules, including this one. Selecting the combined rule selects both triggers; it is not universally disabled merely because the central entry is false.

Consolidation and immutable provenance

Migrated check Reviewed lintdiff source Official promotion incorporated
LroExtension #5639 at 9afb5818 #5652 at 01cc2493
XMSLongRunningOperationProperty #5704 at 2f7e1d5c #5709 at c5e07710

The immutable development implementations, fixtures and migration evidence are unchanged. This is an authorized consolidation of their official destinations, not a repair of either source. The #5709 branch was not merged wholesale or rewritten; its unique behavior is integrated into #5652's existing implementation and canonical suite. No claim is made that #5709's commit history is now an ancestor of this branch.

Historical corpus counts belong to their respective source revisions. They do not establish current combined-rule parity, all-version coverage, or a new corpus run.

Canonical fixture coverage after consolidation

All rule behavior lives in test/rules/lro-missing-polling-metadata.test.ts; no parallel legacy-rule or interaction suite is added.

Source acceptance requirement Current native coverage
Custom PATCH and provider-action 202 responses without metadata Existing synchronous/asynchronous ARM-template negative controls, plus discriminating headerless PATCH and marked-provider POST cases
Standard async resource/provider/custom operations and semantic header customizations Observable native PUT/PATCH/DELETE positives; matched PATCH/DELETE plain-header negatives; one-time counterfactual confirms all three resource positives still trigger
Polling-header verb/status/case selection PUT 201 Azure-AsyncOperation, PATCH 200 mixed-case Location, unmarked POST 202 Location, DELETE 204 lowercase Azure-AsyncOperation
Excluded methods/statuses/header names GET/HEAD, 203/400, Operation-Location/Retry-After and headerless nonmatching operations
Registered resource-instance actions Standard synchronous resource POST with a plain polling header now warns once at the authored operation
Multiple triggers, response variants and shared properties Exact operation targets/counts; one warning for an operation matching both policies and two for two operations sharing headers
Overlapping services and impure metadata resolution Retained registered-linter regression requires exactly one Core diagnostic and zero ARM warnings for the compliant original-uri case
Additional review suggestions Public @OpenAPI.extension override still warns; qualifying header after an unrelated header still warns

Package-level public-entry coverage continues to guard against loading AutoRest or TCGC. The existing ARM feature changeset now describes the combined shipped policy; the separate rulesets internal entry is retained without redundant new notes. Authored docs, generated README/reference, the generated ignored rule page and the manual ARM matrix describe both legacy mappings.

Current validation for selected review fixes (IDs 29–31)

Published in 2a67f1531. The statements below supersede traversal and example details in the historical sections.

  • The native operation listener preserves explicit-service ancestry and concrete endpoint/template eligibility. No shared utility, source lintdiff, rule identifier, activation policy, or trigger changes were made.
  • Removed the redundant provider shared-header fixture; retained the representative two-PUT/shared-response exact-target case, the both-trigger single-warning case, independent trigger/negative cases, and the genuine registered Core resolver-side-effect regression. Added no-service/global, outside-service, and nested concrete/template boundary controls.
  • Canonical LRO suite: 38 passed. Public-entry isolation and ruleset suites: 8 passed. ARM package build (including production typecheck and TypeSpec library lint), root pnpm format, and root pnpm lint: passed. Unrelated Astro-only formatter changes were excluded.
  • Selected-fix validation uses the current checked-in core gitlink cf8712b9, matching the clean core checkout; compiler and HTTP imports resolve within this worktree. Older validation pins below are historical, not the current dependency claim.
  • Simplified the actual authored and regenerated before/after excerpts to PlainLocationHeaders versus semantic ArmLroLocationHeader<FinalResult = Widget> on ArmCustomPatchAsync; Widget and surrounding service setup are assumed, not moved into a shared preamble.
  • Executed both final snippets once in an explicit public-import/service/resource context with the built registered rule enabled: exactly one warning on Microsoft.Contoso.update versus zero diagnostics, retaining numeric 202 in both. The document/snippet hashes and exact setup/targets are recorded outside the repository. This is one-time execution, not continuous Markdown coverage.
  • Only selected Valid IDs 29–31 are implemented in this follow-up. IDs 27–28 were explicitly skipped; their genuine cross-rule side-effect and discriminating async-trigger evidence remains intact. Selected completion does not establish whole-PR readiness, CI success, or reviewer agreement.

Historical validation for the consolidation (before selected review fixes)

  • Baseline rule/isolation selection: 20 passed. The new header-policy expectations then produced 8 expected failures against the original [Swagger Linter Migration] LroExtension + XMSLongRunningOperationProperty -> lro-missing-polling-metadata #5652 implementation.
  • Final focused combined-rule/isolation/rulesets selection: 43 passed (35 canonical rule cases, 1 package-isolation case and 7 ruleset cases).
  • Complete ARM and rulesets suites: 543 passed across 73 files, without changing checked-in timeouts, workers, skips or cache settings.
  • ARM package build, TypeSpec library lint and rulesets build: passed.
  • Required repository pnpm format followed by pnpm lint: passed. Six unrelated Astro-only formatter changes were excluded from the final diff.
  • ARM documentation regeneration: passed, retaining existing unrelated missing-documentation warnings. Final authored/generated Markdown formatting, Chronus status and diff checks passed.
  • Actual final published incorrect/correct snippets were compiled once through the existing ARM tester setup with the built public rule enabled: one exact warning on the then-published Widgets.update versus zero diagnostics. Both retain an explicit 202; document/snippet hashes and target receipts are recorded outside the repository. This is one-time evidence, not continuous Markdown coverage; no bespoke parser is added to the test suite.

The historical consolidation validation recorded core 054fdc2a; current selected-fix validation uses the pin stated above. The full monorepo build, website build and migration corpus were not rerun. New GitHub checks and maintainer review of this combined head remain separate gates; the pre-consolidation Windows benchmark timeout is not represented as resolved by this change.

Historical #5652 promotion notes before consolidation (superseded where the combined contract above differs)

Original Swagger linter

linter code: LroExtension

linter doc: lro-extension.md

  • Inspect OAS2 PUT, PATCH, POST, and DELETE operation objects selected through explicit 202 response keys ($.paths[*][put,patch,post,delete].responses[?(@property == '202')]^^).
  • Require a truthy x-ms-long-running-operation value on the selected operation. The published message calls for true; the check is truthiness rather than strict Boolean equality.
  • Exclude GET (including polling GET) and operations without an explicit 202 response.

Spectral traverses response keys back to their enclosing operation and reports the offending operation path and generated-document range. This emitted-field check does not establish native polling semantics. Existing registered-resource POST/PUT/DELETE prerequisites and comparison-only extension overrides are not evidence that a new native rule should duplicate those policies.

Source TypeSpec lintdiff rule

LroExtension source rule: validator ID LroExtension, canonical validator slug lro-extension, local rule tsp-lintdiff-local-linter/lro-extension.

Canonical repository: Azure/typespec-azure; branch feature/lintdiff-lro-extension; pinned clean reviewed commit 9afb5818fba089835296258049ad7104e8a92c50; source checkout C:\dev\worktrees\lintdiff-lro-extension; development draft #5639. No uncommitted source changes. The named source is assumed done for this run, not claimed to have a separate explicit user done-status confirmation, and remains immutable during promotion.

This incremental refresh follows authorized source repair from f0973f43bffa73169fdde0436566c2534bdab595 to 9afb5818fba089835296258049ad7104e8a92c50, independently reviewed clean in one new Balanced round (review5467572888/request32858013747). It preserves the valid ARM destination adaptations rather than merging the development branch. The reviewed four-file incremental refresh was committed and pushed to the existing canonical promotion branch as 98519f936a2838b5c95620ce4f449c08d20578a5, with parent d2d665bb160a96c384daee82d91b264f98368087; the complete promotion PR still contains ten task files and now records source pin 9afb5818fba089835296258049ad7104e8a92c50.

Destination analysis and naming

The agent-selected destination is @azure-tools/typespec-azure-resource-manager, with concise official name lro-missing-polling-metadata. Catalog applicability Both makes Azure Core a plausible alternative, but the supported native contract depends on ARM isArmCollectionAction to recognize provider/collection POST. Moving that dependency into Core would invert the dependency direction. Existing Core polling-link and ARM header/status-code rules do not establish this missing-metadata condition on the supported custom operations; registered resource-instance POST/PUT/DELETE ownership stays separate.

This is partial supported native coverage, not universal equivalence with the Swagger selector. Availability is opt-in: the resource-manager ruleset registers the new full name with plain false, and the destination feature and rulesets internal disabled-registration changes are separate Chronus entries.

Promoted native behavior and deliberate adaptation

The rule uses compiler listServices, HTTP getHttpService, exact numeric 202 response metadata, ARM isArmCollectionAction, and Azure Core getLroMetadata. PATCH or marked provider/collection POST lacking native LRO metadata receives one warning on the authored operation. Other verbs, unmarked POST, resource-instance POST, absent 202, and present polling metadata do not receive this warning. It examines compiler-program operations rather than emitted version snapshots; corpus version attribution remains separate evidence.

The source semantic-operation Set is preserved and now marks each eligible operation before calling the impure metadata resolver, including compliant operations. Overlapping parent/child HTTP-service traversal reports one warning on the same missing-metadata action, while two operations sharing response headers still produce two authored targets. For a compliant original-uri action without its original-route GET, actual registered linter execution produces exactly one Core diagnostic and zero target warnings, not two Core diagnostics. There is no emitter, OpenAPI-extension/reference-string inference, or TCGC runtime dependency.

The source provider-service guard is mixed ARM/data-plane lintdiff audience isolation, not a metadata prerequisite. The native copy deliberately removes it, following operation-oriented ARM LRO siblings (lro-location-header and retry-after) and the selected official ARM audience. A meaningful providerless PATCH regression asserts exactly one warning with the preserved code/message and authored operation start/end; this is not a source-semantic repair.

Fixture-to-native test mapping

The ten original fixtures map to the exact native titles below. JSON snapshots/extension overrides were not copied, and no snapshot-parity claim is made.

Original lintdiff fixture Native vitest case Coverage note
custom-patch-sync-plain-location it("reports a synchronous custom PATCH returning 202 without polling metadata") Same supported named accepted-response customization; exactly1 authored target.
custom-patch-async-plain-location it("reports the documented async PATCH customization without polling metadata") Actual incorrect authored doc snippet; same LroHeaders customization; exactly1 authored target.
custom-patch-semantic-location it("accepts the documented async PATCH with semantic LRO headers") Actual correct doc snippet preserves202 and fixes metadata;0 warnings.
provider-sync-plain-location it("reports a synchronous provider POST returning 202 without polling metadata") Supported provider sync accepted response;1 warning outside registered resources.
provider-async-plain-location it("reports an async provider POST with plain Location headers") Supported provider async plain Location;1 warning.
provider-semantic-location it("accepts default async provider polling metadata") Default async provider template; native metadata and0 warnings.
compliant-with-template it("accepts standard async resource PATCH polling metadata") Rule-owned compliant resource PATCH. Other CRUD/framework forms not separately ported because GET/PUT/DELETE outside predicate; verb exclusion separately covered.
missing-lro-for-202 it("leaves registered resource-instance POST response-code ownership to the existing rule") Native relevant resource-instance POST exclusion preserved with supported action template and no source suppression copied; response-code enforcement owned elsewhere.
false-lro-extension it("leaves registered resource-instance POST response-code ownership to the existing rule") Same native registered POST exclusion. False emitted extension override is comparison-only, not ported into native tests.
with-lro-extension it("leaves registered resource-instance POST response-code ownership to the existing rule") Same native registered POST exclusion. True emitted extension override is comparison-only, not ported into native tests.
N/A (review regression) it("reports a nested service operation once across overlapping HTTP service traversals") Same nested action, exactly one warning and authored target across overlapping service traversal.
N/A (review regression) it("reports each distinct provider operation once when response headers are shared") Two distinct operations, exactly two warnings with their respective authored targets; no response-model deduplication.
N/A (destination adaptation) it("checks PATCH without provider metadata when the ARM rule is selected") Removed mixed-audience source guard; exactly one same-code/message warning and operation start/end.
N/A (source-repair review regression) it("resolves a compliant operation once before reporting Core diagnostics across overlapping services") Actual registered ARM linter, same eligible compliant nested provider action; exactly1 Core no-operation-at-original-uri,0 target warnings,total1.

The remaining source predicate controls are preserved in the 19-case native suite: synchronous no-202/semantic accepted responses, default async custom/resource/provider templates, excluded verbs, and unmarked POST. The separate namespace-only source case is folded into the meaningful nested dedup regression; no duplicate framework-only namespace traversal test was added. Registered resource-instance POST native exclusion is preserved for the three comparison-only extension fixtures; extension overrides themselves are not native semantics.

All19 logical cases now reside in test/rules/lro-missing-polling-metadata.test.ts. The registered regression deliberately moved from an unpublished standalone file; its logical title/program/assertions are unchanged, but its physical test ID path changed. A fresh raw Tester instance is awaited in the existing beforeEach for every case, and the original18 cases retain their direct rule tester and exact assertions. The new case uses the raw instance's diagnose with the actual registered linter enabled. This removes duplicate initialization in separate files while retaining the repository factory's memoized frozen base filesystem; no mutable instance reuse, module-scope prewarming, assertion suppression, timeout, concurrency or cache changes were introduced. Duplicate initialization is verified, not a proven cause of the historical timeouts.

Migration evidence

Source migration.md contains the focused predicates, retained raw validator witnesses, project explanations, version selection, and corpus declaration. The retained source run attempted 468 ARM projects, compiled 462, and had six unchanged compile failures. Swagger produced 39 findings across 14 projects versus native 14 across 5 projects; 25 intentionally excluded POST/PUT/DELETE findings do not establish universal parity. Missing retained generated-body evidence remains explicitly disclosed in migration.md.

The six unchanged failures are DeviceProvisioningServices, TenantActionGroups, Network/Network, Quota, Resources/deployments, and ServiceLinker. Source17 and strict51 passed; the separate complete596 fixture report retains72 snapshot and3 expectation mismatches proven noncausal and is not claimed green. No source corpus was rerun during promotion.

Validation

  • Complete consolidated native file: 19/19 passed both initially and after final documentation formatting; initial and final affected ARM builds passed.
  • ARM package lint passed; required regen-docs completed naturally.
  • Generated README/reference and ignored rule page were inspected for official name/path/link and native guidance; the alphabetical manual ARM matrix was added.
  • Explicit five-document Prettier --ignore-path NUL write/check passed with each filename processed; .prettierignore/.gitignore unchanged. Ignored generated page is review evidence, not force-staged.
  • Rulesets build passed and rulesets tests 5/5 passed.
  • Full affected ARM package tests: 67 files, 493 tests passed, original checked-in lifecycle/timeouts, no overrides or skips.
  • Actual authored incorrect/correct snippets are read by native tests, with normal ARM Tester imports/usings and only a target-marker comment added. The same ArmCustomPatchAsync accepted response uses named LroHeaders customization: plain Location produces exactly one target-enabled warning at authored update; semantic ArmLroLocationHeader<FinalResult = Widget> plus RetryAfter produces zero, not an exemption. Both compile without unrelated diagnostics.
  • Exact task-owned Chronus entries use LF; Chronus status and final diff hygiene passed. Chronus status also reports pre-existing repository release entries, not additional task edits.

Validation limitations and review state

Validation uses the explicitly dispatched prepared d823d2456182f21fed3a70511edecf14943a3209 base/core b08e0a716343d835197ac49d3e7b0a636cf6a3cd profile. Fetched canonical main advanced to f4d313479a5d3edf12374845500cf943eb1fa534 with newer core/lock/workspace inputs; they were not integrated, and no claim of validation on the newer profile is made. No supplemental repository-wide wrapper or website build was warranted; CI remains authoritative for the Website job.

The historical17/18 providerless marker failure and its authorized correction remain preserved. Cycle1's original standalone registered beforeEach and the separately authorized unchanged retry each timed out at10000ms (18/19); their assertions were not reached. The original instrumented diagnostic passed19/19 with6268.688ms setup, and a separately approved buffered diagnostic passed19/19 with4126.463ms setup. Both probes were restored byte-exactly. Neither diagnostic proves the original timeout cause, and no timeout increase was justified or applied.

The broader authorized recovery consolidated the registered case into the existing suite without changing logical coverage or deadlines. The corrected required selection and all remaining native gates now pass. Native correction1 covers this coherent grouping change; correction2 covers a review-packet .NET relative-path invocation error, repaired with explicit absolute artifact paths and continuation at the next unfinished packet step without replaying passing validation or canonical API queries. Prior failures, exhausted recovery allowances and the unrelated historical full596 limitation remain disclosed.

Fresh outer-owned persistent independent local review is complete: reviewer 13f22e35-64e8-4d7d-901f-ff3582839997 returned CLEAN LOCAL, with actual same-reviewer follow-up acknowledged and the complete ten-file promotion scope, four-file incremental refresh, source pin, 19-case preservation and all 15 validation records inspected. Exact-content publication was approved. This local review is not GitHub approval of the refreshed head.

The first post-push PR read still reported the prior native head despite a successful push and the canonical remote reporting the new commit. That original observation is preserved; subsequent fresh read-only canonical PR, remote and local evidence positively reconciled the actual head to 98519f936a2838b5c95620ce4f449c08d20578a5. Its cause remains unproven, and there was no second push or publication retry.

At publication, fresh promotion GitHub review and backlog drain remained pending, and the original promotion thread PRRT_kwDOKoCXvs6qqJh5 remained unresolved. The owning queue requires verified review of the actual refreshed pushed head and backlog drain before reporting end-to-end success; no old GitHub review is claimed to approve the refreshed commit.

Promotion sync policy

A proven source-semantic gap blocks this promotion rather than being silently fixed only in the official copy. The owning queue must authorize a bounded source-repair cycle and obtain a new clean source review before refreshing native changes and provenance. Source modifications are never part of this promotion invocation.

Review follow-up: documentation-test scope (2026-10-16)

Removed the bespoke Markdown-parsing test in c2afd88, without moving or replacing the parser. All 20 retained literal tests pass, preserving the rule-owned positive/negative and exact authored-target controls. The dependency-closure build and repository format/lint passed.

The actual published incorrect/correct snippets were separately compiled once, with exactly one expected warning versus zero diagnostics and hash/target receipts. Literal tests do not continuously validate Markdown. This supersedes historical description claims about direct Markdown coverage; a standard documentation-testing system is outside this promotion.

Resolver-dedup and no-emitter/no-TCGC guards remain. Both actual PATCH examples were verified to retain numeric 202, so the positive control is not vacuous.

Review cleanup (October 19, 2026)

Moved the registered overlapping-service regression into lro-missing-polling-metadata.test.ts; it still requires exactly one Core diagnostic and zero ARM warnings, covering the resolver side effect. Removed the extra per-rule files and redundant internal entry. Focused package-level public-entry coverage retains the throwing AutoRest/TCGC guards without duplicating rule behavior.

Published in c0f894b. Fresh focused validation: 20 tests passed, package production typecheck, root pnpm format, root pnpm lint, and diff hygiene passed. The full test TypeScript project retains pre-existing diagnostics (25 before, 25 after); the exact-head baseline comparison found no new diagnostics, accounting explicitly for moved tests and any removed duplicate fixture. This is not a claim that the full test TypeScript project is error-free or that pending CI has passed. These current file-layout/coverage statements supersede earlier descriptions of the removed test files; historical validation remains historical.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 625c0cd9-bacc-4f9c-8b96-4ded1932a30a
@microsoft-github-policy-service microsoft-github-policy-service Bot added int:azure-specs Run integration tests against azure-rest-api-specs lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library meta:website TypeSpec.io updates linter Issues related to linter rules labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • ✅ @azure-tools/typespec-azure-resource-manager
  • ✅ @azure-tools/typespec-azure-rulesets
Show changes

@azure-tools/typespec-azure-resource-manager - feature ✏️

Add the lro-missing-polling-metadata lint rule, consolidating LroExtension and XMSLongRunningOperationProperty. Require native polling metadata for PATCH and marked provider/collection POST operations returning 202, and for PUT/PATCH/POST/DELETE operations whose 200, 201, 202, or 204 responses contain Location or Azure-AsyncOperation headers.,> ,> Use asynchronous ARM templates or preserve supported semantic LRO headers. Report once on the authored operation even when both checks apply, and resolve each eligible operation once across overlapping service declarations, including compliant operations.,> ,> The rule is disabled in the central resource-manager ruleset and included in the ARM library's compiler-generated all ruleset.

@azure-tools/typespec-azure-rulesets - internal ✏️

Register the ARM lro-missing-polling-metadata lint rule as disabled in the resource-manager ruleset.

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

📦 Package size report

✅ No notable package size changes compared to the base branch.

14 package(s) with no notable change
Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-azure-rulesets 5.60 KB → 5.96 KB +366 B (+6.4%) 34.59 KB → 34.80 KB +207 B (+0.6%)
@azure-tools/typespec-azure-resource-manager 188.84 KB → 188.91 KB +71 B (+0.0%) 1.13 MB → 1.13 MB +651 B (+0.1%)
@azure-tools/typespec-azure-portal-core 36.26 KB → 36.26 KB -1 B (-0.0%) 242.62 KB → 242.62 KB —
@azure-tools/azure-http-specs 143.53 KB → 143.53 KB — 1.20 MB → 1.20 MB —
@azure-tools/typespec-autorest 87.87 KB → 87.87 KB — 424.17 KB → 424.17 KB —
@azure-tools/typespec-autorest-canonical 7.42 KB → 7.42 KB — 26.00 KB → 26.00 KB —
@azure-tools/typespec-azure-core 136.55 KB → 136.55 KB — 733.30 KB → 733.30 KB —
@azure-tools/typespec-azure-examples 80.15 KB → 80.15 KB — 383.36 KB → 383.36 KB —
@azure-tools/typespec-client-generator-core 248.24 KB → 248.24 KB — 1.32 MB → 1.32 MB —
@azure-tools/typespec-go 263.76 KB → 263.76 KB — 1.35 MB → 1.35 MB —
@azure-tools/typespec-java 20.22 MB → 20.22 MB — 22.51 MB → 22.51 MB —
@azure-tools/typespec-metadata 15.91 KB → 15.91 KB — 62.26 KB → 62.26 KB —
@azure-tools/typespec-python 42.58 KB → 42.58 KB — 166.02 KB → 166.02 KB —
@azure-tools/typespec-ts 530.76 KB → 530.76 KB — 2.67 MB → 2.67 MB —

Packed = gzipped .tgz published to npm. Unpacked = total extracted size. 🆕 added, 🗑️ removed. Packages from the core/ submodule are not included.
🔴 grew · 🟢 shrank — only changes of at least 512 B and 0.5% are marked.

@pkg-pr-new

pkg-pr-new Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@azure-tools/typespec-azure-resource-manager@5652
npm i https://pkg.pr.new/@azure-tools/typespec-azure-rulesets@5652

commit: 19ad246

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.

🟡 Changes recommended

Metadata resolution occurs before deduplication and can emit duplicate diagnostics for operations reached through overlapping service traversals.

1 open finding
What changed in this PR

Adds an opt-in ARM linter rule that detects PATCH and provider/collection POST operations returning 202 without native polling metadata.

Changes:

  • Implements and registers the new rule.
  • Adds comprehensive tests and user documentation.
  • Registers the rule as disabled by default with Chronus entries.
File Description
lro-missing-polling-metadata.ts Implements metadata validation.
lro-missing-polling-metadata.test.ts Tests supported and excluded cases.
lro-missing-polling-metadata.md Documents usage and remediation.
src/​linter.ts Registers the rule.
resource-manager.ts Disables the rule by default.
README.md Lists the rule.
reference/​linter.md Updates generated reference documentation.
arm-rules.md Adds the migration mapping.
lro-missing-polling-metadata-arm.md Describes the ARM feature change.
lro-missing-polling-metadata-rulesets.md Describes ruleset registration.

🧠 Review effort: Balanced


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

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

Mirror the reviewed LroExtension source repair and consolidate the registered regression while preserving fresh per-test setup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 625c0cd9-bacc-4f9c-8b96-4ded1932a30a

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.

🟢 Approval recommended

The implementation, registration, documentation, and regression coverage are consistent with the stated opt-in behavior.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@msyyc
Yuchao Yan (msyyc) marked this pull request as ready for review October 10, 2026 02:18
Yuchao Yan (msyyc) added a commit that referenced this pull request Oct 10, 2026
## Original Swagger linter

linter code:
[LroExtension](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/az-common.ts)

linter doc:
[lro-extension.md](https://github.com/Azure/azure-openapi-validator/blob/main/docs/lro-extension.md)

- [x] Inspect OAS2 PUT, PATCH, POST and DELETE operations with an
explicit `202` response.
- [x] Require a truthy `x-ms-long-running-operation` on the selected
operation; an absent or false extension violates the original check.
- [x] Exempt GET and operations without an explicit `202` response.

The Spectral selector
`$.paths[*][put,patch,post,delete].responses[?(@Property == '202')]^^`
walks from each selected response back to its operation, where the
extension is checked. The diagnostic concerns the operation's
extension/missing extension, not whether its `Location` header actually
describes polling. Copying that extension-based behavior would miss
native semantic failures and duplicate existing ARM prerequisites.

## Migrated native TypeSpec behavior

Mapping: **LroExtension → `lro-extension`**
(`tsp-lintdiff-local-linter/lro-extension`). Coverage is deliberately
**partial**, limited to supported uncovered ARM semantics.

The maintained resource-manager ruleset already owns registered
resource-instance POST/PUT/DELETE response-code checks. This migration
does not duplicate them. It checks PATCH and ARM-marked
collection/provider POST operations with exact HTTP `202` responses,
using compiler `listServices`, HTTP `getHttpService`, ARM
`isArmCollectionAction`, and Azure Core `getLroMetadata`. Supported
customized `ArmCustomPatchAsync` and `ArmProviderActionAsync` headers
can retain a plain `Location` header while losing native polling
metadata; those operations receive one warning on the authored
operation. Semantic LRO headers/default async templates are compliant.
Supported synchronous template response customizations are also covered.

The temporary mixed ARM/data-plane lintdiff runner uses service-root
`getArmProviderNamespace` only for isolation. The documented promotion
adaptation removes that guard when the official ARM ruleset supplies the
audience boundary. Production logic uses compiler/HTTP/Core/ARM only: no
emitter, OpenAPI extensions, TCGC, reference-string inference, or unsafe
version mutation.

Polling metadata, not emitted extension overrides or historical Swagger
snapshots, defines the native contract. Version attribution is assessed
separately against corpus-selected API versions; this is not an
all-historical-version or universal Swagger-equivalence claim.

The earlier nested-service warning regression retains one target warning
for an overlapping missing-metadata operation and two for distinct
operations sharing response types. The cycle-1 repair additionally marks
each eligible semantic Operation visited **before** impure metadata
resolution, including compliant operations. A real registered-package
regression uses nested services that are both ARM-provider marked, a
standard async provider action, and original-uri final state with no GET
at that route. It now produces **exactly one Azure Core
`no-operation-at-original-uri` diagnostic, zero `lro-extension`
diagnostics, and no other diagnostics**, rather than resolving metadata
twice. Eligibility, service isolation, warning severity/message, and
authored Operation targets are unchanged.

## Migration evidence and validation

[Migration note: latest results, complete project accounting,
supported-shape evidence, version attribution and
limitations](https://github.com/Azure/typespec-azure/blob/9afb5818fba089835296258049ad7104e8a92c50/packages/typespec-lintdiff/test/fixtures/LroExtension/migration.md).

- Scoped four-file formatting/check, package build and
changed-TypeScript lint passed before the new commit.
- Focused native tests: **17 passed** (the original 16 plus the actual
registered-linter regression). The original overlap-warning1 and
distinct-operation-warning2 controls remain covered.
- All four affected fixture groups passed with unchanged
snapshot/expectation enforcement: **51 cases**. Explicitly reviewed
ambient expectations, intentional Swagger/native discrepancies, and the
existing mapped-compliance advisory are preserved; this is not a claim
of 51 universally equivalent or universally clean cases.
- Required fresh full ARM corpus: **468 attempted, 462 compiled
successfully**, with **six unchanged compile failures**
(DeviceProvisioningServices, TenantActionGroups, Network/Network, Quota,
Resources/deployments and ServiceLinker;
duplicate-body/missing-uri-param). Their details and impact are
disclosed in the migration note.
- Retained Swagger results: **39 diagnostics / 14 projects**; native
results: **14 diagnostics / 5 projects**. Five projects overlap; nine
are validator-only; none are TypeSpec-only. The 25 intentional
exclusions are POST14, PUT6 and DELETE5, belonging to documented
prerequisites/out-of-contract operations rather than unexplained
supported-native misses.
- The fresh representative/full corpus after the cycle-1 production
repair preserved all 14 native diagnostic identities and all six known
compilation failures.
- Validation retained the prepared source profile: Core
`a6137cac43a727ce0c2656364fd72d50c272ee4a`, integrated base
`adf0d2865887d9e12609d7a4d398b96211510a85`, and checked-in runner
settings. The fetched migration base had advanced to
`b4fdf202afdda010789557603b571f046f0ca70c`; the branch/Core/profile were
not moved or replayed.
- The historical complete **596-case fixture baseline** had **72
snapshot mismatches and three expectation mismatches** previously
established as noncausal. It was not rerun this cycle and is not
represented as a fully green suite.
- A fresh persistent independent local reviewer found no significant
issues in the complete **57-file** task diff, including the registered
regression, after an actual same-reviewer follow-up. The new incremental
commit changes exactly four approved files.
- Generated corpus output was archived and restored through the
exact-digest reviewed cleanup plan (971 generated changes); no generated
coverage, logs, dependency manifests, Core gitlink changes or skill
changes are committed.

Published source head:
[`9afb5818fba089835296258049ad7104e8a92c50`](9afb581),
parent `f0973f43bffa73169fdde0436566c2534bdab595`, on the existing
development branch.

This remains the development-stage draft. A **new current-head GitHub
review is pending**; the earlier `f097` review does not cover this
commit. [Official promotion draft
#5652](#5652) remains
unchanged at `d2d665bb160a96c384daee82d91b264f98368087` with its
previous `f097` source pin, pending a clean new source review and an
explicitly authorized incremental refresh. Neither PR is merged by this
workflow.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 625c0cd9-bacc-4f9c-8b96-4ded1932a30a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain literal rule fixtures and package-isolation regressions. Published examples were independently executed and recorded as one-time session evidence; no continuous Markdown coverage is claimed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Combine LroExtension and XMSLongRunningOperationProperty in one rule with operation-level diagnostics, shared resolver deduplication, and canonical acceptance coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@msyyc Yuchao Yan (msyyc) changed the title [Swagger Linter Migration] LroExtension -> lro-missing-polling-metadata [Swagger Linter Migration] LroExtension + XMSLongRunningOperationProperty -> lro-missing-polling-metadata Oct 20, 2026
Preserve the combined LRO migration mapping alongside the new resource-missing-read and use-resource-path-for-put mappings from main.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Yuchao Yan (msyyc) and others added 2 commits October 21, 2026 12:11
Use the native operation listener within explicit services, preserve concrete endpoint eligibility and resolver side effects, and consolidate duplicate shared-header coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use observable native async positives and matched plain-header negatives without HTTP metadata assertions. Retain the registered resolver-side-effect regression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@msyyc

Copy link
Copy Markdown
Member Author

Copilot resolve the merge conflicts in this pull request

…extension

# Conflicts:
#	website/src/content/docs/docs/howtos/ARM/arm-rules.md

Co-authored-by: msyyc <70930885+msyyc@users.noreply.github.com>

Copilot AI commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved the main merge conflict in merge commit 983132c60.

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

int:azure-specs Run integration tests against azure-rest-api-specs lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library linter Issues related to linter rules meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants