Skip to content

[Swagger Linter Migration] GuidUsage - #5336

Open
Yuchao Yan (msyyc) wants to merge 9 commits into
Azure:mainfrom
msyyc:promote-guid-usage-to-arm
Open

[Swagger Linter Migration] GuidUsage#5336
Yuchao Yan (msyyc) wants to merge 9 commits into
Azure:mainfrom
msyyc:promote-guid-usage-to-arm

Conversation

@msyyc

@msyyc Yuchao Yan (msyyc) commented Aug 28, 2026

Copy link
Copy Markdown
Member

Original Swagger linter

The original rule performs these checks:

  • Traverses the unresolved ARM OpenAPI document recursively.
  • Selects every node whose property name is format and value is uuid.
  • Covers named definitions, parameters, request and response bodies, response headers, and any other emitted UUID format occurrence.
  • Reports an error at each emitted format: uuid node with Azure API review guidance.

How the Swagger linter works

The Spectral rule runs the unresolved JSONPath $..[?(@property === 'format' && @ === 'uuid')] and applies falsy. It has no authored-shape exemptions and does not resolve references before traversal. Its diagnostic location is the emitted format node, so one TypeSpec declaration may be reported repeatedly when it is expanded across paths, operations, schemas, visibility variants, or API versions.

That representation also produces findings which should not be copied into a native TypeSpec rule: imported Azure.Core.RequestIdResponseHeader expansions are library-owned, and retained Swagger can contain stale Azure.Core.uuid definitions absent from the current authored TypeSpec surface. The native rule therefore diagnoses actionable authored targets and deduplicates them rather than matching emitted occurrence counts.

Source TypeSpec lintdiff rule

  • Validator rule ID: GuidUsage
  • Local lintdiff rule: tsp-lintdiff-local-linter/guid-usage
  • Canonical validator slug: guid-usage
  • Source rule: guid-usage.ts
  • Source branch: feature/lintdiff-guid-usage
  • Source commit used for promotion: cf3f5db38bf3a540c929a1d2ba9b7fea1638d7f7
  • Source worktree: C:\dev\worktrees\lintdiff-guid-usage
  • Uncommitted source-rule changes: none

The user marked this source rule done for promotion. The lintdiff source, fixtures, snapshots, manifests, and documentation were not modified during promotion.

Destination analysis

The promoted rule belongs in @azure-tools/typespec-azure-resource-manager:

  • validator metadata declares applicability: ARM and sources: ["arm"]
  • every focused fixture is inferred as resource-manager
  • the implementation needs ARM provider namespace discovery, resolved ARM resources, resource lifecycle/list/action operations, and generated resource-key parameters
  • the migration evidence specifically evaluates ARM services and ARM emitter behavior

@azure-tools/typespec-azure-core was considered because its no-format rule recommends Azure.Core.uuid instead of @format("uuid"). It is not equivalent: no-format governs decorator usage across Azure APIs, while this rule prohibits semantic UUID wire shapes throughout ARM APIs, including UUID scalar aliases and template-generated parameters. Placing the rule in core would also require removing its ARM-only resource and provider semantics.

The official rule is named no-uuid, following the TypeSpec convention for a banned construct rather than carrying the validator slug into the user-facing rule name.

How the promoted TypeSpec linter works

@azure-tools/typespec-azure-resource-manager/no-uuid:

  • limits named-model traversal to ARM service namespaces
  • resolves ARM HTTP services with getAllHttpServices
  • checks parameters, request bodies, response bodies, and response headers
  • recognizes scalar-level and property-level UUID formats
  • follows custom scalar bases, arrays, records, tuples, unions, inherited properties, and cloned sourceProperty chains
  • inspects unreferenced named models because the OpenAPI emitter can retain those definitions
  • excludes imported library declarations and client-only namespaces
  • deduplicates diagnostics by authored ModelProperty or Operation
  • maps generated resource-name parameters back to authored ARM operations

Current main retains a library-owned source property for generated resource-key parameters. The official-package adaptation therefore prioritizes the resource-key operation fallback before the generic source-property lookup. This preserves the lintdiff rule's intended authored-operation diagnostic target for both typed and formatted ResourceNameParameter instantiations.

The rule is available but registered as false in the resource-manager ruleset so promotion does not introduce diagnostics into existing Azure service specs.

Fixture-to-native test mapping

Original lintdiff fixture Native vitest case Coverage note
uuid-property it("reports a UUID-typed model property") Direct UUID model property
uuid-query-parameter it("reports a UUID-typed query parameter") Resolved HTTP query parameter
uuid-template-parameter it("reports a UUID-typed resource name template parameter") Typed generated resource key; asserts four authored operation diagnostics
uuid-template-format-parameter it("reports a UUID-formatted resource name template parameter") Formatted generated resource key; asserts four authored operation diagnostics
uuid-body it("reports a direct UUID request body") Direct request payload
uuid-response it("reports a direct UUID response body") Direct response payload
uuid-custom-scalar it("reports a custom scalar derived from UUID") Custom scalar base traversal
uuid-format-property it("reports a property-level UUID format") Property format after model spread
uuid-array-property it("reports an array property containing UUID values") Array container traversal
non-uuid-shapes it("allows non-UUID shapes and UUIDs in client-only namespaces") Compliant strings and excluded client-only model
unreachable-uuid-property it("reports a UUID property on an unreferenced named model") Unreferenced emitted named model
N/A (review regression) it("reports UUID values nested in records, tuples, and unions") Container and union traversal
N/A (review regression) it("reports a UUID-typed response header") Authored response-header target
N/A (review regression) it("deduplicates a property reached through declarations and HTTP payloads") Authored-target deduplication

Migration evidence

See GuidUsage/migration.md for the declared focused tests, real-service comparison, latest full-corpus counts, one-sided project explanations, compile failures, and remaining uncertainty.

Validation

  • ARM dependency closure build
  • focused no-uuid test: 14 passed
  • ARM package build and lint
  • ARM documentation regeneration
  • ARM package tests: 385 passed
  • Azure rulesets build and tests: 4 passed
  • repository format check and required pre-commit pnpm format && pnpm lint
  • website dependency closure and website build
  • Chronus status and LF line-ending validation
  • two focused promotion code reviews with no high-confidence findings
  • git diff --check

Validation blocker

pnpm validate:pr reported that the already-tested branch was behind a newly advanced origin/main, then produced no further progress for five minutes. It was stopped under the bounded validation policy. The narrower native validations listed above completed successfully.

Promotion sync policy

Any newly discovered semantic gap should block this promotion until the user explicitly reopens lintdiff repair. The done lintdiff source is not modified as part of promotion.

NOTE: heavy

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 Aug 28, 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 Aug 28, 2026
@github-actions

github-actions Bot commented Aug 28, 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-uuid ARM lint rule, migrated from the Swagger GuidUsage validator rule.

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

Register the ARM no-uuid lint rule as disabled in the resource manager ruleset.

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

📦 Package size report

2 packages changed size, +9.14 KB (+0.1%) packed overall.

Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-client-generator-core 229.57 KB → 237.09 KB +7.52 KB (+3.3%) 🔴 1.23 MB → 1.27 MB +43.32 KB (+3.4%) 🔴
@azure-tools/typespec-azure-rulesets 5.27 KB → 5.36 KB +90 B (+1.7%) 32.97 KB → 33.53 KB +576 B (+1.7%) 🔴
11 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 +740 B (+0.0%) 15.03 MB → 15.04 MB +3.11 KB (+0.0%)
@azure-tools/typespec-azure-resource-manager 179.19 KB → 179.77 KB +600 B (+0.3%) 1.08 MB → 1.08 MB +2.83 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.46 KB → 42.46 KB +5 B (+0.0%) 193.15 KB → 193.15 KB
@azure-tools/azure-http-specs 146.76 KB → 146.76 KB +4 B (+0.0%) 1.16 MB → 1.16 MB
@azure-tools/typespec-ts 540.59 KB → 540.59 KB -4 B (-0.0%) 2.60 MB → 2.60 MB
@azure-tools/typespec-autorest-canonical 7.42 KB → 7.42 KB 26.00 KB → 26.00 KB
@azure-tools/typespec-azure-core 130.84 KB → 130.84 KB 709.84 KB → 709.84 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.

@pkg-pr-new

pkg-pr-new Bot commented Aug 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 5dded4a

@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-Session: cf125def-85b2-462d-8902-7ac7beb588a3
);
}
},
root: () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why do you need to make your own traverse here? can't you just use the linter engine, this seems like this should be a pretty simple rule

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The extra traversal is intentional because this rule is trying to cover the resolved HTTP projection of the API while reporting on actionable authored TypeSpec targets. The regular linter traversal handles ordinary declarations, but it does not fully cover generated ARM HTTP shapes with a useful diagnostic location.

For example:

model Widget is TrackedResource<WidgetProperties> {
  ...ResourceNameParameter<
    Resource = Widget,
    KeyName = "widgetName",
    SegmentName = "widgets",
    Type = Azure.Core.uuid
  >;
}

@armResourceOperations
interface Widgets {
  get is ArmResourceRead<Widget>;
}

This emits an HTTP path parameter with format: uuid, which the Swagger GuidUsage rule reports. The corresponding widgetName model property is generated from an ARM library template and is library-owned, so reporting from a basic modelProperty listener would point into code the service author cannot meaningfully fix or suppress. The HTTP/resource traversal recognizes it as the resource key and maps the finding back to the authored Widgets.get operation.

The same projection traversal covers direct ArmResponse<uuid> bodies and formats applied to generated HTTP parameters. It also lets us exclude imported library-owned findings and deduplicate repeated emitted occurrences. These cases came from the lintdiff corpus investigation and have focused tests in this PR.

Some of the recursive type inspection may still be refactorable, but replacing the resolved HTTP traversal with only semantic listeners would narrow the migrated rule's established coverage or change its diagnostic targets.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

hhm really don't like that by that reasoning every single rule should do their own traversal due to the same limitation. I think if this is critical and can't be hacked in the diagnostic target resolution function right now we need to figure out a better way built in for this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Can't find a better solution. Let us hold on this PR for now and see if other PRs have similar request for traversal or we could find other solution. CC catalinaperalta

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can you not just check modelProperty type(and any other types you want to check) and report on the model property? The typespec engine should report template instantiation trace if it happens in a template

@msyyc Yuchao Yan (msyyc) Sep 4, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Timothee Guerin (@timotheeguerin) Yes, this works for the ordinary cases, and I refactored the rule in afd2b72 to use modelProperty and operation listeners for authored properties, parameters, headers, direct return types, containers, unions, and custom scalars. The resolved HTTP traversal for ordinary parameters, request/response bodies, and headers has been removed.

There is one ARM-specific exception. An instantiated ResourceNameParameter.name property does carry a template mapper, so the compiler can produce an instantiation trace. However, its primary source location remains the library declaration in Azure.ResourceManager.ResourceNameParameter. The linter filters library-targeted diagnostics before presenting related instantiation locations, so reporting that generated property directly produces no user-visible diagnostic.

This is not just theoretical in the migration corpus: there are 9 UUID resource-name declarations across 6 projects (8 across 5 successfully compiled projects; Quota was excluded by its compile failure), producing 35 Swagger operation-parameter findings. Dropping the case would therefore create a known gap in 5 of the 46 projects detected by the final TypeSpec corpus run. (detailed report is here: https://github.com/Azure/typespec-azure/blob/feature/lintdiff-migration-new/packages/typespec-lintdiff/test/fixtures/GuidUsage/migration.md)

As a compromise, the only remaining HTTP projection logic now finds resolved ARM resource-key parameters and maps those library-owned generated parameters to their authored operations. Everything else uses the standard linter traversal. I also added coverage for ArmResponse<Azure.Core.uuid> to ensure a UUID hidden behind a library response wrapper remains detected without recursively reporting project response models. The implementation is reduced by 184 lines, and all 16 focused tests still pass.

Comment thread packages/typespec-azure-resource-manager/src/rules/no-uuid.ts Outdated

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 can misclassify imported library declarations and misses unreferenced named scalar and union UUID schemas.

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

Pull request overview

Adds the ARM no-uuid linter rule migrated from Swagger GuidUsage.

Changes:

  • Implements UUID detection across ARM schemas and HTTP payloads.
  • Adds rule tests and documentation.
  • Registers the rule disabled by default and records the feature release.
File summaries
File Description
no-uuid.ts Implements UUID traversal and diagnostics.
no-uuid.test.ts Tests supported UUID shapes.
no-uuid.md Documents rationale and examples.
linter.ts Registers the rule.
resource-manager.ts Adds the disabled ruleset entry.
README.md Lists the new rule.
linter.md Updates generated website reference.
Chronus change Records affected packages and feature.
Review details

Suppressed comments (1)

packages/typespec-azure-resource-manager/src/rules/no-uuid.md:37

  • The LintDiff equivalent should deep-link to the canonical GuidUsage entry (R3017) in the OpenAPI automated-guidelines document rather than the legacy validator documentation.
This rule corresponds to the Swagger validator rule [GuidUsage](https://github.com/Azure/azure-openapi-validator/blob/6243cb01c16c7535cd3b8df6f45fbeb3c095ed7f/docs/guid-usage.md).
  • Files reviewed: 8/8 changed files
  • Comments generated: 5
  • Review effort level: Balanced

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

Comment thread packages/typespec-azure-resource-manager/src/rules/no-uuid.ts
Comment thread packages/typespec-azure-resource-manager/src/rules/no-uuid.ts Outdated
Comment thread packages/typespec-azure-resource-manager/README.md
Comment thread packages/typespec-azure-resource-manager/src/rules/no-uuid.md
Comment thread packages/typespec-azure-resource-manager/test/rules/no-uuid.test.ts
Yuchao Yan (msyyc) and others added 2 commits September 2, 2026 12:47
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread packages/typespec-azure-resource-manager/src/rules/no-uuid.ts Outdated
Yuchao Yan (msyyc) and others added 3 commits September 3, 2026 10:44
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.

3 participants