Skip to content

Anchor ARM resource identity to read and create operations - #4851

Open
Dapeng Zhang (ArcturusZhang) wants to merge 24 commits into
Azure:mainfrom
ArcturusZhang:arcturus/resolve-arm-resource-identity
Open

Anchor ARM resource identity to read and create operations#4851
Dapeng Zhang (ArcturusZhang) wants to merge 24 commits into
Azure:mainfrom
ArcturusZhang:arcturus/resolve-arm-resource-identity

Conversation

@ArcturusZhang

@ArcturusZhang Dapeng Zhang (ArcturusZhang) commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

  • Change ARM resource resolution so concrete resource identities are seeded only from registered read/createOrUpdate operations
  • Replace permissive operation-path resource ID inference with strict ARM resource instance path parsing
  • Append lifecycle/list/action operations only when they match an already detected resource identity
  • Add regression coverage for list-only/action-only operations not creating resources and create-only operations still creating resources
  • Include the resolveArmResources design proposal and related linter candidates

Designed resource detection flow

  1. Collect candidate resource model details from listArmResources(program). These are registered TypeSpec resource models, not yet concrete ARM resources.

    • Current implementation largely already does this.
  2. Find identity operations for each candidate model: read and createOrUpdate.

    • Required change: previous implementation considered all registered ARM operations equally during resource creation, including list, action, update, delete, and checkExistence.
    • Covered by this PR: resources are now seeded only from read and createOrUpdate.
  3. Use identity operation paths as candidate resource instance paths. The resolver should trust the registered ARM operation kind; HTTP verb/response-shape correctness should be enforced by linters.

    • Required change: previous implementation derived resource identity from every operation path.
    • Covered by this PR: only read/createOrUpdate paths can establish resource identity.
  4. Parse and validate each candidate path as an ARM resource instance path.

    • Required change: previous parser synthesized resource IDs from non-instance paths, especially list/action paths, and fabricated providerless resource identities beyond known exceptions.
    • Covered by this PR: getResourcePathElements was removed and replaced with strict parseArmResourceInstancePath, which requires a literal /providers/{namespace} segment except for known providerless exceptions such as tenant, subscription, resource group, and explicit generic resource-id parameter paths.
  5. Group candidates by normalized resource identity: provider namespace, resource type segments, literal path segments case-insensitively, and variable path segments by position while ignoring variable names.

    • Required change: previous grouping did not consistently compare full normalized instance paths and could merge across paths/scopes when explicit resource names matched.
    • Covered by this PR: resource identity grouping now uses normalized instance-path comparison for identity operations.
  6. Create one concrete ResolvedResource per identity group. read + createOrUpdate on the same normalized path become one resource; different valid paths become separate resources; createOrUpdate alone can create a resource; list/action alone cannot.

    • Required change: previous list and action operations could create a ResolvedResource.
    • Covered by this PR: added tests for list-only/action-only not creating resources and create-only creating a resource.
  7. Derive stable resource facts from the canonical instance path: resourceInstancePath, resourceType, provider namespace, scope, resource name parameter or singleton key, and parent candidate information.

    • Required change: previous implementation derived these facts independently from each operation path; singleton metadata is model/decorator-based rather than path-based.
    • Partially covered by this PR: resourceInstancePath/resourceType now come from strict identity paths. Path-based singleton cleanup remains future work.
  8. Append remaining operations only to already-detected resources: lifecycle operations by matching normalized instance path, list operations by detected-resource-ID prefix, and action operations under the detected resource instance path.

    • Required change: previous detection and operation grouping happened in one phase, allowing non-identity operations to define resources. Previous list matching also parsed list paths to reconstruct possible resources.
    • Covered by this PR: non-identity operations are appended only after detected identities exist. List operations now attach only to the closest detected resource whose normalized resource ID has the list request path as a prefix. Non-prefix list mappings are intentionally left as a TODO and do not create resource identities.
  9. Leave unmatched operations for provider/non-resource handling. They should not invent new resources.

    • Required change: previous registered ARM operations that failed association could be skipped and also excluded from providerOperations.
    • Not covered by this PR.
  10. Resolve parent and scope relationships after the full resource set is known, using normalized path comparison. Missing parents should be skipped rather than synthesized as empty resources.

    • Required change: previous implementation can synthesize empty parent/scope resources and return ExternalResource for ambiguous external scopes.
    • TODO: clarify scope representation. Concrete external scopes can currently be synthesized as ResolvedResource entries, while ambiguous/generic external scopes use "ExternalResource" as an unresolved-external sentinel. We should decide whether to keep that sentinel, replace it with undefined or a structured unresolved scope, and remove the unused parent/scope fields from the internal ResolvedResourceOperations staging type if they remain unused.
    • Not covered by this PR.

Validation

  • pnpm --filter @azure-tools/typespec-azure-resource-manager exec tsc -p tsconfig.build.json --noEmit
  • pnpm --filter @azure-tools/typespec-azure-resource-manager exec vitest run test/resource-resolution.test.ts --testNamePattern "parseArmResourceInstancePath"
  • Diagnostic-tolerant resolver behavior script verified list-only=0, create-only=1, full resource prefix-list/action attachment=1/1, resource group exception, and generic resource-id exception
  • Full pnpm --filter @azure-tools/typespec-azure-resource-manager exec vitest run test/resource-resolution.test.ts is currently blocked by baseline experimental-feature warnings from compiler/agent TypeSpec files

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 8, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 985a77a

@azure-sdk-automation

azure-sdk-automation Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

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

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

Fix resolveArmResources resource identity detection to seed resources from strict ARM resource instance paths instead of inferring resource IDs from list or action operation paths.

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚡ Benchmark Results

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

Metric Baseline Current Change
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 26.7ms 🔴 28.2ms +5.3% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 27.8ms 🔴 29.5ms +6.0% 🔴
Full details – comparing 651bb03 vs baseline rolling-baseline-4df8556-2398555 (rolling baseline (20 main runs))
Metric Baseline Current Change
total 🔴 1.01s 🔴 1.05s +3.4%
loader 🟡 307.6ms 🟡 318.5ms +3.5%
resolver 🟢 40.5ms 🟢 41.2ms +1.8%
checker 🟡 365.7ms 🟡 379.9ms +3.9%
validation 🟢 85.1ms 🟢 86.9ms +2.1%
 ↳ validation/@azure-tools/typespec-azure-core 🟡 12.6ms 🟡 13.3ms +5.3%
 ↳ validation/@typespec/http 🟡 15.5ms 🟡 16.3ms +4.7%
 ↳ validation/@typespec/rest 🟢 1.6ms 🟢 1.7ms +2.7%
 ↳ validation/@typespec/versioning 🔴 51.4ms 🔴 51.6ms +0.4%
 ↳ validation/compiler 🟢 3.9ms 🟢 3.9ms +1.7%
linter 🟡 215.3ms 🟡 222.6ms +3.4%
 ↳ linter/@azure-tools/typespec-azure-core/auth-required 🟢 0.1ms 🟢 0.1ms +7.4%
 ↳ linter/@azure-tools/typespec-azure-core/bad-record-type 🟢 0.6ms 🟢 0.6ms +1.7%
 ↳ linter/@azure-tools/typespec-azure-core/byos 🟢 8.4ms 🟢 8.6ms +2.8%
 ↳ linter/@azure-tools/typespec-azure-core/casing-style 🟢 1.5ms 🟢 1.5ms +0.9%
 ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance 🟢 0.2ms 🟢 0.2ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-core/documentation-required 🟢 1.9ms 🟢 2.0ms +2.2%
 ↳ linter/@azure-tools/typespec-azure-core/friendly-name 🟢 1.4ms 🟢 1.4ms +2.0%
 ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required 🟢 0.4ms 🟢 0.4ms +3.2%
 ↳ linter/@azure-tools/typespec-azure-core/known-encoding 🟢 0.5ms 🟢 0.5ms +3.0%
 ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required 🟢 0.8ms 🟢 0.8ms +3.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch 🟢 0.7ms 🟢 0.7ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union 🟢 1.0ms 🟢 1.0ms +0.1%
 ↳ linter/@azure-tools/typespec-azure-core/no-enum 🟢 0.2ms 🟢 0.3ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes 🟢 0.3ms 🟢 0.3ms +0.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops 🟢 0.2ms 🟢 0.2ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-format 🟢 0.8ms 🟢 0.8ms +2.1%
 ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric 🟢 0.8ms 🟢 0.9ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 26.7ms 🔴 28.2ms +5.3% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage 🟢 2.1ms 🟢 2.1ms +1.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator 🟢 0.2ms 🟢 0.2ms +5.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-nullable 🟢 0.4ms 🟢 0.4ms +4.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime 🟢 2.0ms 🟢 2.0ms +1.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-openapi 🟢 2.3ms 🟢 2.4ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-private-usage 🟢 3.2ms 🟢 3.2ms +1.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 27.8ms 🔴 29.5ms +6.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-response-body 🔴 33.4ms 🔴 35.0ms +4.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟢 0.1ms 🟢 0.1ms +1.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch 🟢 7.7ms 🟢 8.1ms +5.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params 🟢 0.4ms 🟢 0.4ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator 🟢 0.1ms 🟢 0.2ms +5.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-unknown 🟢 0.4ms 🟢 0.4ms +3.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union 🟢 0.8ms 🟢 0.8ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version 🟢 0.4ms 🟢 0.4ms -0.4%
 ↳ linter/@azure-tools/typespec-azure-core/request-body-problem 🟢 0.5ms 🟢 0.5ms +0.8%
 ↳ linter/@azure-tools/typespec-azure-core/require-versioned 🟢 0.1ms 🟢 0.1ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 32.6ms 🔴 33.6ms +2.9%
 ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body 🟢 0.7ms 🟢 0.7ms +4.9%
 ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model 🟢 0.5ms 🟢 0.5ms +0.7%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-names 🟢 7.6ms 🟢 8.0ms +5.3%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations 🟢 0.3ms 🟢 0.3ms +1.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🔴 21.0ms 🔴 22.0ms +4.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations 🟢 0.3ms 🟢 0.3ms +9.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🟡 12.1ms 🟡 12.5ms +3.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key 🟢 0.2ms 🟢 0.2ms -0.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage 🟢 0.1ms 🟢 0.1ms +1.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 5.0ms 🟢 4.6ms -6.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-feature-file-usage-discourage 🟢 0.1ms 🟢 0.1ms -4.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🟡 17.1ms 🟡 17.0ms -0.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 0.6ms 🟢 0.6ms -1.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes 🟢 1.4ms 🟢 1.4ms +2.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes 🟢 0.2ms 🟢 0.2ms -4.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment 🟢 0.4ms 🟢 0.4ms -3.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property 🟢 0.4ms 🟢 0.4ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator 🟢 0.1ms 🟢 0.1ms -0.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb 🟢 0.2ms 🟢 0.2ms -4.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property 🟢 0.3ms 🟢 0.3ms +4.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format 🟢 0.2ms 🟢 0.2ms +0.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars 🟢 0.5ms 🟢 0.5ms +1.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern 🟢 0.1ms 🟢 0.1ms +3.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation 🟢 0.5ms 🟢 0.6ms +2.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🟢 9.0ms 🟢 9.1ms +1.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch 🟢 0.8ms 🟢 0.8ms -4.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars 🟢 0.4ms 🟢 0.4ms +0.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state 🟢 0.4ms 🟢 0.4ms +2.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels 🟢 0.2ms 🟢 0.2ms +2.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties 🟢 0.4ms 🟢 0.4ms +0.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation 🟢 0.1ms 🟢 0.1ms +13.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 19.7ms 🔴 20.6ms +5.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint 🟢 0.1ms 🟢 0.1ms +1.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers 🟢 1.0ms 🟢 1.0ms -1.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model 🟢 0.3ms 🟢 0.3ms +2.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props 🟢 0.3ms 🟢 0.3ms -1.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-reserved-resource-property 🟢 0.2ms 🟢 0.2ms -0.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation 🟢 0.5ms 🟢 0.5ms -0.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 29.8ms 🔴 30.7ms +3.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope 🟢 0.4ms 🟢 0.4ms +1.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name 🟢 0.4ms 🟢 0.4ms -1.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop 🟢 5.4ms 🟢 5.1ms -6.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type 🟢 0.7ms 🟢 0.7ms -2.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression 🟢 0.3ms 🟢 0.3ms -2.1%
 ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict 🟢 2.3ms 🟢 2.3ms +0.8%
 ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix 🟢 1.7ms 🟢 1.7ms +1.4%
emit 🔴 6.04s 🔴 6.28s +3.9%
 ↳ emit/Azure-Tools 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@azure-tools/typespec-autorest 🟢 125.4ms 🟢 129.9ms +3.6%
 ↳ emit/@azure-tools/typespec-python 🔴 2.25s 🔴 2.35s +4.1%
 ↳ emit/typespec 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@typespec/http-client-js 🔴 571.9ms 🔴 587.6ms +2.7%
 ↳ emit/@typespec/openapi3 🟢 107.9ms 🟢 112.4ms +4.1%
 ↳ emit/@typespec/openapi3/compute 🟢 93.8ms 🟢 97.7ms +4.2%
 ↳ emit/@typespec/openapi3/write 🟢 13.9ms 🟢 14.4ms +3.7%

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)

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

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
{ operationGroup: "Employees", name: "listBySubscription", kind: "list" },
{ operationGroup: "Employees", name: "listByResourceGroup", kind: "list" },
],
lists: [{ operationGroup: "Employees", name: "listByResourceGroup", kind: "list" }],

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.

not sure if this is an issue.

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.

seems like we need both

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.

yeah I am thinking the same thing right now.
I will see where it goes wrong and get it back.

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.

Agreed. The strict prefix rule was too narrow for list operations at wider scopes. I opened #5080 to track the complete matching-rule design, and added an issue-linked TODO in the matcher.

In this PR I am applying the focused case we know is valid: subscription-list operations can attach to resource-group-scoped resources when the concrete provider/type path is the same. That brings this test back to expecting both listBySubscription and listByResourceGroup, without letting list operations create resource identities.


🤖 arcturus-copilot

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.

Follow-up: refined in 9ef00922 to avoid a scope-specific exception. The matcher now prefers direct list-path prefix matches first; if none exists, it falls back to matching by concrete provider/type path. The resource side reuses parseArmResourceInstancePath, while list/collection paths use a small collection-path parser.


🤖 arcturus-copilot

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.

Follow-up in 553cf2bc: getListMatchDistance now trims the ARM scope prefix before comparing path lengths, so prefix-match ranking is based on the resource-type tail rather than subscription/resource-group/tenant scope length.


🤖 arcturus-copilot

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

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f

@markcowl Mark Cowlishaw (markcowl) left a comment

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.

I need a little more time to go over the test changes, but will add in the external integration ci job as well.

@@ -0,0 +1,92 @@
# Linter candidates for `resolveArmResources`

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.

I think we should probably make this into an issue Most of this validation is being added as part of the new linters for typespec suppression, but it would be nice to have this to track

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.

sure I could create an issue to track these candidates. do you prefer one per one candidate or we have a overall issue to contain all of these?


`resolveArmResources(program)` should produce a complete, deterministic, version-aware description of the ARM provider shape represented by the TypeSpec program.

The API should make the version dimension explicit. For an unversioned TypeSpec program, it should return one provider result. For a versioned TypeSpec program, it should return provider results for each declared service version so downstream emitters and analyzers can reason about the resource shape that exists in each API version.

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.

I am skeptical of this requiremntt for two reasons:

  • It assumes that every consumer wants a version-projection for each version in the program
  • it assumes that every consumer does not want a version-independent canonical view of the resources (this was the original reason for this API, in fact).

Instead, I would suggest that either a versioned program is passed in (for which helpers could be provided) or there is a mechanism that allows projecting the result.

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.

yeah I agree. but per my investigation in this issue, currently passing in a version mutated program does not really change the result, just FYI.

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.

Addressed in caf191e by removing the per-version result requirement from the proposal and documenting that
esolveArmResources uses the view represented by the input program; version-specific analysis should be layered on top with version-projected programs/helpers.


🤖 arcturus-copilot

| "Subscription"
| "ResourceGroup"
| "ManagementGroup"
| "Scope"

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.

We should add "ServiceGroup"

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.

Addressed in caf191e: added ServiceGroup to the proposal's ArmResourceScope union and added code-side ArmResourceScope typing including ServiceGroup.


🤖 arcturus-copilot


## High-level flow

1. Find the ARM provider namespace with `resolveProviderNamespace(program)`.

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.

versioning doesn't seem to be mentioned here, how will we handle versions?

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.

I think our design is:
this API just uses the program which has been (or not) mutated by versioning. therefore this API does not do anything about versioning explicitly.
is this understanding correct?
if so, we do not need to mention versioning here at all.

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.

Addressed in caf191e. The high-level flow remains focused on resource resolution, and versioning is now described earlier as an input-program/projection concern rather than as a resolver step.


🤖 arcturus-copilot

}
for (let i = 0; i < resourceSegments.length; i += 2) {
const typeSegment = resourceSegments[i];
const nameSegment = resourceSegments[i + 1];

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 name segment isn't a variable segment?

@ArcturusZhang Dapeng Zhang (ArcturusZhang) Jul 27, 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.

then it should be a singleton resource. the handling of singleton resource is not covered (or not fully covered) in this PR yet.
there are two kinds of singleton resources:

  1. the resource's name is a constant
  2. the resource's name is not a constant but an enum - we should expect fixed enum.
    last time we did a change in the resource result schema to let this api to support both - the singletonresourcename can take a single value or an array of names.

FYI I have to stop the modification in some point to prevent this PR to contain every change we would like, because it might make the PR very hard to review. What do you think?
I was trying to split the changes we would like to have when making the change, but those changes kind of are linked with each other, therefore the PR's size just grew and grew

{ operationGroup: "Employees", name: "listBySubscription", kind: "list" },
{ operationGroup: "Employees", name: "listByResourceGroup", kind: "list" },
],
lists: [{ operationGroup: "Employees", name: "listByResourceGroup", kind: "list" }],

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.

seems like we need both

@markcowl Mark Cowlishaw (markcowl) added the int:azure-specs Run integration tests against azure-rest-api-specs label Jul 23, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
…resource-identity

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

Copilot-Session: 10e564a2-4523-48ae-821e-a1c3e878765f
@github-actions

Copy link
Copy Markdown
Contributor

📦 Package size report

1 package changed size, +841 B (+0.0%) packed overall.

Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-azure-resource-manager 171.29 KB → 172.04 KB +778 B (+0.4%) 1.04 MB → 1.04 MB +8.28 KB (+0.8%) 🔴
12 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 +64 B (+0.0%) 15.03 MB → 15.03 MB
@azure-tools/typespec-azure-portal-core 42.40 KB → 42.40 KB -1 B (-0.0%) 192.87 KB → 192.87 KB
@azure-tools/azure-http-specs 146.21 KB → 146.21 KB 1.16 MB → 1.16 MB
@azure-tools/typespec-autorest 80.93 KB → 80.93 KB 395.06 KB → 395.06 KB
@azure-tools/typespec-autorest-canonical 7.42 KB → 7.42 KB 26.00 KB → 26.00 KB
@azure-tools/typespec-azure-core 129.41 KB → 129.41 KB 702.62 KB → 702.62 KB
@azure-tools/typespec-azure-rulesets 5.16 KB → 5.16 KB 32.09 KB → 32.09 KB
@azure-tools/typespec-client-generator-core 226.23 KB → 226.23 KB 1.22 MB → 1.22 MB
@azure-tools/typespec-go 244.79 KB → 244.79 KB 1.25 MB → 1.25 MB
@azure-tools/typespec-metadata 15.91 KB → 15.91 KB 62.26 KB → 62.26 KB
@azure-tools/typespec-python 46.22 KB → 46.22 KB 180.83 KB → 180.83 KB
@azure-tools/typespec-ts 524.71 KB → 524.71 KB 2.53 MB → 2.53 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.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants