Skip to content

Document resolveArmResources design proposal#4793

Draft
ArcturusZhang wants to merge 2 commits into
Azure:mainfrom
ArcturusZhang:arcturus/resolve-arm-resources-design
Draft

Document resolveArmResources design proposal#4793
ArcturusZhang wants to merge 2 commits into
Azure:mainfrom
ArcturusZhang:arcturus/resolve-arm-resources-design

Conversation

@ArcturusZhang

@ArcturusZhang ArcturusZhang commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

  • Add a proposal for a version-aware resolveArmResources design
  • Add linter candidates needed to support trusting registered ARM operation kinds

Current implementation mismatches

Area Current implementation Proposed design mismatch
Version-aware output Returns a single Provider and caches by Namespace -> Provider. Proposal expects explicit provider/version dimensions with one result per service version.
Provider discovery resolveProviderNamespace returns the first namespace with ARM provider state. Proposal shape allows multiple providers; current API effectively resolves one.
Resource detection source Any registered ARM operation can create a ResolvedResource. Proposal says only Read and CreateOrUpdate paths should create concrete resources.
List/action can create resources list and action operations can initialize a new resource group. Proposal says list/action should only append to already detected resources.
No separate append pass Operations are grouped while resources are being discovered. Proposal separates detection from appending other lifecycle/list/action operations.
Unmatched registered operations Registered ARM operations that cannot resolve resource info are skipped and also excluded from providerOperations. Proposal says operations that cannot be associated with detected resources should remain available for provider-level/non-resource handling.
Associated operations still exist ResolvedResource includes associatedOperations, and other operations are attached there. Proposal removed associatedOperations.
Path identity is operation-derived Resource identity is derived from each operation path. Proposal says canonical resource identity should be derived from grouped Read/CreateOrUpdate instance paths.
Path parser is permissive for non-instance paths List operations can synthesize instance paths by appending {name}. Proposal wants candidate paths validated/parsed as ARM resource instance paths for detection.
Normalized comparison incomplete Resource matching normalizes some provider/type/scope casing, but parent matching is case-sensitive and full path variable names are not consistently ignored. Proposal requires normalized comparison whenever comparing resource paths/identities.
Parent handling Missing parents are synthesized as empty ResolvedResource records. Proposal says skip missing parents instead of synthesizing empty parent resources.
Scope handling Scope may be ExternalResource or a synthesized ResolvedResource. Proposal removed ExternalResource and wants structured references only when concrete.
Parent/scope reference shape parent and resource-valued scope are full ResolvedResource objects. Proposal uses lightweight ResolvedResourceReference.
Singleton detection Singleton metadata comes from @singleton state and model key-property union. Proposal says singleton metadata should be path-based from literal or closed-literal name segments.
Lifecycle arrays optional/undefined Lifecycle buckets are initialized with undefined values. Proposal shape uses arrays for every lifecycle bucket.
Resource model detail naming remains current listArmResources returns ArmResourceDetails, deduped by qualified TypeSpec model name. Proposal notes this is really candidate resource model detail; implementation still uses the old model and may collapse version/projected distinctions.
Protocol/response linters not part of implementation Current decorators register operation kinds but resolver does not enforce the proposed linter contracts. Proposal relies on new linters for lifecycle verb consistency, read/create response shape, and list item shape.

Related issue: customAzureResource-based converted specs

Opened #4798 for a real-world mismatch found while comparing legacy/Swagger-shaped resource detection with resolveArmResources output.

Network is the main case: the .NET management emitter comparison found 140 legacy-detected resources, but resolveArmResources returns 0 resources and 776 non-resource methods for specification/network/resource-manager/Microsoft.Network/Network. The spec uses legacy/custom resource bases marked with @Azure.ResourceManager.Legacy.customAzureResource(#{ isAzureResource: true }), which means the current TypeSpec-based detection path can intentionally diverge from Swagger-shaped legacy detection.

This needs either a spec-side resolution, if Network can be migrated to the supported Azure.ResourceManager.Legacy.CustomAzureResource<true> pattern and future converted specs can be prevented from using the unsupported form, or a library-side resolution in resolveArmResources if this custom-resource shape must continue to be recognized.

Related Azure SDK analysis PR

The generated comparison reports and manual root-cause notes are preserved in Azure/azure-sdk-for-net#60620.

Validation

  • Documentation-only change

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library label Jul 1, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 9b8ffc4

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

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

⚡ Benchmark Results

⚠️ 15 metric(s) regressed above the +5% threshold:

Metric Baseline Current Change
total 🔴 715.2ms 🔴 771.7ms +7.9% 🔴
loader 🟡 203.6ms 🟡 226.7ms +11.3% 🔴
resolver 🟢 21.9ms 🟢 34.1ms +56.1% 🔴
checker 🟡 229.7ms 🟡 281.0ms +22.3% 🔴
validation 🟢 52.0ms 🟢 67.8ms +30.4% 🔴
 ↳ validation/@azure-tools/typespec-azure-core 🟢 7.6ms 🟢 9.4ms +23.2% 🔴
 ↳ validation/@typespec/http 🟢 7.4ms 🟡 11.7ms +58.7% 🔴
 ↳ validation/@typespec/versioning 🔴 33.6ms 🔴 42.0ms +24.9% 🔴
 ↳ validation/compiler 🟢 2.0ms 🟢 3.2ms +57.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🟢 6.8ms 🟡 10.1ms +49.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🟢 5.5ms 🟢 9.0ms +64.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 2.0ms 🟢 4.3ms +115.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🟡 11.9ms 🟡 13.0ms +8.8% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🟢 5.7ms 🟢 7.0ms +22.7% 🔴
 ↳ emit/@azure-tools/typespec-autorest 🟢 89.0ms 🟢 98.2ms +10.3% 🔴
Full details – comparing 55d86b5 vs baseline rolling-baseline-a6f8ccf-364b924 (rolling baseline (20 main runs))
Metric Baseline Current Change
total 🔴 715.2ms 🔴 771.7ms +7.9% 🔴
loader 🟡 203.6ms 🟡 226.7ms +11.3% 🔴
resolver 🟢 21.9ms 🟢 34.1ms +56.1% 🔴
checker 🟡 229.7ms 🟡 281.0ms +22.3% 🔴
validation 🟢 52.0ms 🟢 67.8ms +30.4% 🔴
 ↳ validation/@azure-tools/typespec-azure-core 🟢 7.6ms 🟢 9.4ms +23.2% 🔴
 ↳ validation/@typespec/http 🟢 7.4ms 🟡 11.7ms +58.7% 🔴
 ↳ validation/@typespec/rest 🟢 0.8ms 🟢 1.4ms +76.8%
 ↳ validation/@typespec/versioning 🔴 33.6ms 🔴 42.0ms +24.9% 🔴
 ↳ validation/compiler 🟢 2.0ms 🟢 3.2ms +57.0% 🔴
linter 🟢 157.7ms 🟢 161.6ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-core/auth-required 🟢 0.0ms 🟢 0.1ms +141.4%
 ↳ linter/@azure-tools/typespec-azure-core/bad-record-type 🟢 0.3ms 🟢 0.5ms +64.9%
 ↳ linter/@azure-tools/typespec-azure-core/byos 🟢 6.5ms 🟢 6.3ms -2.4%
 ↳ linter/@azure-tools/typespec-azure-core/casing-style 🟢 0.8ms 🟢 1.2ms +53.1%
 ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance 🟢 0.1ms 🟢 0.1ms +64.6%
 ↳ linter/@azure-tools/typespec-azure-core/documentation-required 🟢 1.0ms 🟢 1.7ms +65.6%
 ↳ linter/@azure-tools/typespec-azure-core/friendly-name 🟢 0.8ms 🟢 1.1ms +43.5%
 ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required 🟢 0.2ms 🟢 0.3ms +40.2%
 ↳ linter/@azure-tools/typespec-azure-core/known-encoding 🟢 0.3ms 🟢 0.4ms +12.8%
 ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required 🟢 0.4ms 🟢 0.6ms +63.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch 🟢 0.3ms 🟢 0.6ms +78.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union 🟢 0.4ms 🟢 0.8ms +102.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-enum 🟢 0.1ms 🟢 0.2ms +164.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes 🟢 0.1ms 🟢 0.2ms +66.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops 🟢 0.1ms 🟢 0.1ms +21.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-format 🟢 0.6ms 🟢 0.7ms +7.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric 🟢 0.5ms 🟢 0.7ms +34.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 21.1ms 🟡 19.1ms -9.7% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage 🟢 1.3ms 🟢 1.5ms +16.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator 🟢 0.1ms 🟢 0.2ms +52.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-nullable 🟢 0.3ms 🟢 0.3ms +14.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime 🟢 1.3ms 🟢 1.5ms +11.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-openapi 🟢 2.1ms 🟢 2.0ms -3.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-private-usage 🟢 2.2ms 🟢 2.4ms +12.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 22.4ms 🟡 19.8ms -11.5% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-response-body 🔴 26.3ms 🔴 24.7ms -5.9% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟢 0.0ms 🟢 0.1ms +144.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch 🟢 5.7ms 🟢 5.4ms -4.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params 🟢 0.2ms 🟢 0.3ms +31.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator 🟢 0.1ms 🟢 0.1ms +67.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-unknown 🟢 0.2ms 🟢 0.3ms +17.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union 🟢 0.4ms 🟢 0.6ms +45.4%
 ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version 🟢 0.2ms 🟢 0.3ms +45.1%
 ↳ linter/@azure-tools/typespec-azure-core/request-body-problem 🟢 0.3ms 🟢 0.4ms +14.8%
 ↳ linter/@azure-tools/typespec-azure-core/require-versioned 🟢 0.0ms 🟢 0.0ms +179.8%
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 24.5ms 🔴 24.4ms -0.4%
 ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body 🟢 0.4ms 🟢 0.5ms +37.0%
 ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model 🟢 0.3ms 🟢 0.4ms +17.1%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-names 🟢 6.0ms 🟢 5.4ms -11.4%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations 🟢 0.1ms 🟢 0.2ms +37.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🟢 6.8ms 🟡 10.1ms +49.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations 🟢 0.0ms 🟢 0.2ms +299.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🟢 5.5ms 🟢 9.0ms +64.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key 🟢 0.1ms 🟢 0.2ms +48.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage 🟢 0.1ms 🟢 0.1ms +30.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 2.0ms 🟢 4.3ms +115.1% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🟡 11.9ms 🟡 13.0ms +8.8% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 0.4ms 🟢 0.5ms +27.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes 🟢 0.7ms 🟢 1.4ms +114.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes 🟢 0.0ms 🟢 0.2ms +225.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment 🟢 0.3ms 🟢 0.4ms +37.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property 🟢 0.2ms 🟢 0.3ms +74.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator 🟢 0.0ms 🟢 0.1ms +173.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb 🟢 0.1ms 🟢 0.1ms +44.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property 🟢 0.1ms 🟢 0.2ms +68.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format 🟢 0.1ms 🟢 0.2ms +147.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars 🟢 0.3ms 🟢 0.4ms +26.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern 🟢 0.0ms 🟢 0.1ms +244.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation 🟢 0.2ms 🟢 0.4ms +90.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🟢 5.7ms 🟢 7.0ms +22.7% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch 🟢 0.4ms 🟢 0.7ms +73.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars 🟢 0.2ms 🟢 0.3ms +28.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state 🟢 0.2ms 🟢 0.3ms +100.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels 🟢 0.1ms 🟢 0.2ms +66.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties 🟢 0.2ms 🟢 0.3ms +60.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation 🟢 0.0ms 🟢 0.1ms +274.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 15.1ms 🟡 13.6ms -9.8% 🟢
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint 🟢 0.0ms 🟢 0.1ms +166.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers 🟢 0.4ms 🟢 0.9ms +119.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model 🟢 0.2ms 🟢 0.2ms +39.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props 🟢 0.1ms 🟢 0.3ms +135.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation 🟢 0.2ms 🟢 0.3ms +44.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 22.2ms 🔴 21.2ms -4.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope 🟢 0.2ms 🟢 0.3ms +58.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name 🟢 0.2ms 🟢 0.3ms +69.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop 🟢 4.3ms 🟢 4.7ms +8.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type 🟢 0.4ms 🟢 0.6ms +31.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression 🟢 0.1ms 🟢 0.2ms +237.5%
 ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict 🟢 1.3ms 🟢 1.7ms +33.9%
 ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix 🟢 0.4ms 🟢 1.3ms +201.4%
emit 🔴 5.63s 🔴 4.59s -18.4% 🟢
 ↳ emit/@Azure-Tools 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@azure-tools/typespec-autorest 🟢 89.0ms 🟢 98.2ms +10.3% 🔴
 ↳ emit/@azure-tools/typespec-python 🔴 2.15s 🔴 1.69s -21.4% 🟢
 ↳ emit/@typespec 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@typespec/http-client-js 🔴 481.1ms 🔴 446.6ms -7.2% 🟢
 ↳ emit/@typespec/openapi3 🟢 80.4ms 🟢 83.3ms +3.5%
 ↳ emit/@typespec/openapi3/compute 🟢 70.1ms 🟢 72.4ms +3.3%
 ↳ emit/@typespec/openapi3/write 🟢 10.1ms 🟢 10.6ms +5.2%

Averaged across 3 specs (azure-arm-resource-manager, azure-core-dataplane, azure-full).
Threshold: changes > ±5% are highlighted.
🟢 Fast · 🟡 Moderate (stages >200ms, rules >10ms) · 🔴 Slow (stages >400ms, rules >20ms)

}

interface ResolvedResource {
type: Model;

@RodgeFu RodgeFu Jul 3, 2026

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.

what' if the resource has different Model for post/get/put/...? Will the API already have helped merged them? we will need the API to expose these different models if not so that the consumers can further process them.

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.

this type here (type is not a good property name, I will change it later) represents the "resource model" of this resource. theoretically, you could consider this as the "entity model" of this ARM resource on the service side.
This is not showing any request or response types.
But some operations indeed have some rules, which I have put in the linter candidates.
For instance, read operation (get) should always return the same model as the resource model. createOrUpdate operation (put) should always return the same model as the resource model as well. In real world, createOrUpdate operation can use a different model as request.
action operations (usually post) do not have constraint on request/response type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lib:azure-resource-manager Issues for @azure-tools/typespec-azure-core library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants