Skip to content

[Swagger Linter Migration] UnSupportedPatchProperties - #5384

Open
Yuchao Yan (msyyc) wants to merge 3 commits into
mainfrom
promote-un-supported-patch-properties-to-arm
Open

[Swagger Linter Migration] UnSupportedPatchProperties#5384
Yuchao Yan (msyyc) wants to merge 3 commits into
mainfrom
promote-un-supported-patch-properties-to-arm

Conversation

@msyyc

@msyyc Yuchao Yan (msyyc) commented Sep 3, 2026

Copy link
Copy Markdown
Member

Original Swagger linter

The original rule performs these checks on every ARM Swagger PATCH operation:

  • Rejects writable top-level id.
  • Rejects writable top-level name.
  • Rejects writable top-level type.
  • Rejects writable top-level location.
  • Rejects writable properties.provisioningState.
  • Exempts readOnly: true properties.
  • Exempts properties whose x-ms-mutability excludes update.

How the Swagger linter works

The ARM Spectral ruleset selects PATCH operations under both paths and x-ms-paths with resolved references enabled. validatePatchBodyParamProperties finds the first body parameter, resolves its schema through getProperties, checks the configured top-level denylist, then separately resolves the properties bag and checks provisioningState. Every failure targets the PATCH body parameter rather than the individual schema property.

For each selected property, the validator treats readOnly: true or an x-ms-mutability array without update as exempt. Spectral's resolved traversal can drop annotations that are siblings of $ref; the migration corpus confirmed false positives for referenced read-only provisioningState and immutable location properties. The TypeSpec rule intentionally preserves the authored lifecycle semantics instead of reproducing that validator defect. Swagger also reports emitted occurrences, while one authored TypeSpec property can be reused across operations and versions.

Source TypeSpec lintdiff rule

  • Validator rule ID: UnSupportedPatchProperties
  • Local lintdiff rule: unsupported-patch-properties
  • Canonical validator slug: un-supported-patch-properties
  • Source branch: feature/lintdiff-un-supported-patch-properties
  • Merged source revision: de8d12e0244eb128604d2c4208f19325837fa852
  • Source repair PR: [Swagger Linter Migration] UnSupportedPatchProperties (origin) #5386
  • Source worktree: C:\dev\worktrees\lintdiff-un-supported-patch-properties
  • Source state: clean; there were no uncommitted rule changes
  • Source rule: unsupported-patch-properties.ts

The user marked this source rule done after its provider-namespace ownership repair merged. Promotion did not modify the lintdiff source, fixtures, snapshots, package metadata, or documentation.

Destination analysis

The rule belongs in @azure-tools/typespec-azure-resource-manager. Its semantics are ARM RPC-Patch-V1-02, every fixture uses ARM service shapes, catalog metadata says applicability: ARM and sources: ["arm"], and the validation report infers the resource-manager ruleset. Azure Core is not a plausible destination because the rule is not shared data-plane guidance.

Existing official rules do not duplicate this behavior. arm-resource-patch rejects fields absent from the resource but permits envelope fields such as name, type, and location; custom ARM PATCH templates also accept arbitrary patch models. The promoted rule therefore closes the documented official coverage gap rather than changing an existing rule.

The official name is no-unsupported-patch-properties, following the TypeSpec no-<thing> convention instead of retaining the validator's historical casing and wording. The rule is explicitly registered as false in the resource-manager ruleset so promotion does not immediately add diagnostics to existing service specifications.

How the promoted TypeSpec linter works

When enabled in the ARM ruleset, the rule visits operations and selects HTTP PATCH requests with bodies. The official implementation deliberately omits the lintdiff source's provider-namespace guard: lintdiff enables ARM and data-plane rules together and must self-scope, while the destination ARM ruleset already supplies this applicability boundary. This matches neighboring operation-based ARM rules and avoids suppressing diagnostics solely because provider decoration is absent or malformed.

The rule unwraps nullable single-model bodies while leaving scalar and multi-model unions compliant. For the PATCH model and nested properties model, it walks inherited properties, resolves their application/json encoded names, and uses HTTP metadata plus PATCH request visibility to determine whether each property reaches the payload. Lifecycle visibility distinguishes writable properties from read-only or create-only properties. Diagnostics target authored project properties; library-originated properties fall back to the operation. This avoids emitting duplicate diagnostics for generated Swagger occurrences while preserving actionable source locations.

Promotion-specific adaptations are the official rule name, removal of the lintdiff-only applicability guard, canonical documentation URL, and package registration. Property-selection, visibility, and diagnostic semantics remain aligned with the source rule.

Fixture-to-native test mapping

Original lintdiff fixture Native vitest case Coverage note
patch-with-id-name/main.tsp it("reports writable id, name, and type properties") Three direct writable top-level reserved properties and diagnostic cardinality.
nested-arm-namespace/main.tsp it("reports unsupported properties in nested ARM namespaces") Nested namespace ownership regression from the merged source repair.
global-operation-compliant/main.tsp it("does not require provider namespace decoration when the ARM rule is enabled") Destination adaptation: the ARM ruleset owns applicability, so the official rule does not retain lintdiff's mixed-ruleset guard.
patch-with-location-provisioning-state/main.tsp it("reports writable location and properties.provisioningState on a nullable body") Nullable body unwrapping plus top-level and nested violations.
encoded-inherited-properties/main.tsp it("reports inherited properties by their encoded JSON names") Inherited properties, encoded JSON names, nested inheritance, and three diagnostics.
readonly-immutable-properties-compliant/main.tsp it("accepts read-only and immutable reserved properties") Read-only identity and provisioning state plus create-only location.
readonly-ref-validator-discrepancy/main.tsp it("accepts a read-only referenced provisioning state") Preserves intended semantics instead of Spectral's resolved $ref false positive.
non-object-bodies-compliant/main.tsp it("accepts scalar and multi-model-union bodies") Neither body shape exposes a single selected object schema.

Migration evidence

The checked-in migration.md records focused fixture coverage, the real-service comparison, latest full-corpus counts, all one-sided project explanations, compile-failure exclusions, and the conclusion that no semantic uncertainty remains.

Validation

  • ARM dependency-closure build
  • Focused native test: 8/8 passed
  • ARM package build and lint
  • ARM documentation regeneration and Prettier check
  • Rulesets build and tests: 4/4 passed
  • ARM package tests: 402/402 passed
  • Repository format and lint
  • Focused promotion review: no findings

Validation blocker

The broad website-skipped pnpm validate:pr completed all nine phases on the original promotion commit but failed because two unrelated full-repository tests exceeded their existing timeouts:

  • @azure-tools/typespec-java eng/scripts/core-commit.test.ts: 5-second timeout
  • @azure-tools/typespec-azure-playground-website compile Tracked Resource: 10-second timeout

The same run passed branch freshness, the full build, lint, format, spelling, and diff hygiene. The narrower native validation above is complete and was rerun after the destination adaptation.

Promotion sync policy

If review identifies a semantic gap, this promotion should be blocked until the user explicitly reopens lintdiff repair. Destination-only applicability adaptation must be documented and validated rather than copied or removed mechanically.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@msyyc Yuchao Yan (msyyc) added the int:azure-specs Run integration tests against azure-rest-api-specs label Sep 3, 2026
@microsoft-github-policy-service microsoft-github-policy-service Bot added lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library meta:website TypeSpec.io updates linter Issues related to linter rules labels Sep 3, 2026
@msyyc
Yuchao Yan (msyyc) requested a lite review from Copilot September 3, 2026 05:37
@github-actions

github-actions Bot commented Sep 3, 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 no-unsupported-patch-properties ARM linter rule, which reports writable resource identity, location, and provisioning state properties in PATCH request bodies.

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

Register the ARM no-unsupported-patch-properties lint rule as disabled in the resource manager ruleset.

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

The rule’s ARM/provider-namespace detection is incorrect (can miss nested namespaces and misclassify global ops), and the suggested regression test should be added to prevent recurrence.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR promotes the Swagger validator rule UnSupportedPatchProperties into the official @azure-tools/typespec-azure-resource-manager linter as no-unsupported-patch-properties, adds native Vitest coverage, and wires the rule into ARM documentation and ruleset registration (disabled by default).

Changes:

  • Adds the new ARM linter rule implementation and documentation (no-unsupported-patch-properties).
  • Adds a native Vitest suite covering the migrated scenarios.
  • Registers the rule in the ARM linter + ruleset and updates ARM docs/readme + Chronus changeset.
File summaries
File Description
website/src/content/docs/docs/libraries/azure-resource-manager/reference/linter.md Adds the new rule to the ARM linter rule reference table.
packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts Registers the rule in the ARM ruleset as disabled by default.
packages/typespec-azure-resource-manager/test/rules/no-unsupported-patch-properties.test.ts Adds native Vitest coverage for the migrated rule behavior.
packages/typespec-azure-resource-manager/src/rules/no-unsupported-patch-properties.ts Implements the new ARM linter rule that flags non-patchable PATCH body properties.
packages/typespec-azure-resource-manager/src/rules/no-unsupported-patch-properties.md Adds end-user rule documentation and examples.
packages/typespec-azure-resource-manager/src/linter.ts Adds the rule to the ARM linter’s exported rule list.
packages/typespec-azure-resource-manager/README.md Adds the rule to the package rule table.
.chronus/changes/promote-un-supported-patch-properties-2026-09-03-13-20-00.md Adds a changeset describing the new rule promotion and default-disabled registration.
Review details

Suppressed comments (1)

packages/typespec-azure-resource-manager/src/rules/no-unsupported-patch-properties.ts:191

  • Rename the helper function to match what it actually does (Lifecycle visibility checks) so it stays consistent with the call site name and doesn’t imply x-ms-mutability handling.
function canSharePropertyUsingReadonlyOrXmsMutability(
  program: Program,
  property: ModelProperty,
): boolean {
  • Files reviewed: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 100f545

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📦 Package size report

3 packages changed size, +13.21 KB (+0.1%) packed overall.

Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-client-generator-core 229.48 KB → 237.09 KB +7.61 KB (+3.3%) 🔴 1.23 MB → 1.27 MB +43.76 KB (+3.5%) 🔴
@azure-tools/typespec-ts 536.72 KB → 540.59 KB +3.87 KB (+0.7%) 🔴 2.58 MB → 2.60 MB +21.12 KB (+0.8%) 🔴
@azure-tools/typespec-azure-rulesets 5.27 KB → 5.36 KB +91 B (+1.7%) 32.97 KB → 33.58 KB +624 B (+1.8%) 🔴
10 package(s) with no notable change
Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-java 13.51 MB → 13.51 MB +744 B (+0.0%) 15.03 MB → 15.04 MB +3.11 KB (+0.0%)
@azure-tools/typespec-azure-resource-manager 179.18 KB → 179.75 KB +584 B (+0.3%) 1.08 MB → 1.09 MB +2.90 KB (+0.3%)
@azure-tools/typespec-autorest 81.01 KB → 81.23 KB +222 B (+0.3%) 395.40 KB → 396.61 KB +1.21 KB (+0.3%)
@azure-tools/typespec-azure-portal-core 42.40 KB → 42.46 KB +68 B (+0.2%) 192.91 KB → 193.15 KB +243 B (+0.1%)
@azure-tools/azure-http-specs 146.71 KB → 146.76 KB +58 B (+0.0%) 1.16 MB → 1.16 MB +239 B (+0.0%)
@azure-tools/typespec-azure-core 130.84 KB → 130.84 KB -1 B (-0.0%) 709.84 KB → 709.84 KB
@azure-tools/typespec-autorest-canonical 7.42 KB → 7.42 KB 26.00 KB → 26.00 KB
@azure-tools/typespec-go 261.39 KB → 261.39 KB 1.34 MB → 1.34 MB
@azure-tools/typespec-metadata 15.91 KB → 15.91 KB 62.26 KB → 62.26 KB
@azure-tools/typespec-python 42.22 KB → 42.22 KB 164.91 KB → 164.91 KB

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.

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

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

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 rule implementation is wired correctly, covered by targeted native tests, and is registered as disabled-by-default so it won’t introduce unexpected diagnostics for existing projects.

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

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.

2 participants