Azure / Azure/typespec-azure

[resource-manager] resolveArmResources returns zero resources for customAzureResource-based converted specs

Open
#4,798 2 comments 0 reactions 1 assignee Assigned to @ArcturusZhang View on GitHub
needs-area
Dominant language
TypeScript
Stars
27
Forks
90
Avg merge
1d 22h
Merged PRs (30d)
156

Description

## Description

`resolveArmResources` currently returns no resources for converted/legacy TypeSpec specs that model ARM resources through `Azure.ResourceManager.Legacy.customAzureResource(#{ isAzureResource: true })` or equivalent custom resource bases, instead of the standard `TrackedResource` / `ProxyResource` templates.

This creates an intentional mismatch between:

- resource detection based on the Swagger-shaped/legacy path, which can still identify these resources from paths and legacy/custom resource metadata; and
- resource detection based on TypeSpec `resolveArmResources`, which only sees resources registered into the ARM library resource registry.

If the intended design is that only `Azure.ResourceManager.Legacy.CustomAzureResource` (or another specific library-supported pattern) should be used, then existing converted specs need to be fixed and we need a way to guarantee future converted specs will not use the older/incorrect custom-resource shape. Otherwise, `resolveArmResources` likely needs to support this custom-resource pattern from the library side so the two detection paths do not diverge.

## Real case: Network

The Network management TypeSpec spec is a concrete example.

Spec location used by the .NET SDK generation:

```yaml
# azure-sdk-for-net/sdk/network/Azure.ResourceManager.Network/tsp-location.yaml
directory: specification/network/resource-manager/Microsoft.Network/Network
commit: 280622e57e9bd85a10d355dd5295144dd25af1d9
repo: Azure/azure-rest-api-specs
```

In the generated schema comparison from the .NET management emitter:

```text
legacy resource detection: 140 resources, 35 non-resource methods
resolveArmResources detection: 0 resources, 776 non-resource methods
```

So `resolveArmResources` does not retain even one Network ARM resource; all resource operations fall through as non-resource methods.

Representative Network TypeSpec patterns:

```typespec
@Http.Private.includeInapplicableMetadataInPayload(false)
model ApplicationGateway extends Common.Resource {
@visibility(Lifecycle.Read)
@path
@key("applicationGatewayName")
@segment("applicationGateways")
name: string;
}

@Azure.ResourceManager.Legacy.feature(Features.applicationGateway)
@armResourceOperations(#{ omitTags: true })
interface ApplicationGateways { ... }
```

The shared/custom resource bases in `Network/models.tsp` use the legacy custom resource decorator, for example:

```typespec
@Azure.ResourceManager.Legacy.customAzureResource(#{ isAzureResource: true })
model ProxyResource { ... }

@Azure.ResourceManager.Legacy.customAzureResource(#{ isAzureResource: true })
model CommonTrackedResource extends CommonResource { ... }

@Azure.ResourceManager.Legacy.customAzureResource(#{ isAzureResource: true })
model WritableResource { ... }
```

This is exactly the kind of spec shape converted from Swagger where the old detection logic can still infer ARM resources, but `resolveArmResources` returns none.

## Relationship to #3430 / #3748

#3430 was closed by #3748, which introduced:

```typespec
@Http.Private.includeInapplicableMetadataInPayload(false)
@customAzureResource(#{ isAzureResource: isResource })
model CustomAzureResource {}
```

That appears to mean the preferred/validated solution is to use `Azure.ResourceManager.Legacy.CustomAzureResource` rather than hand-applying `@customAzureResource(#{ isAzureResource: true })` on arbitrary custom base models.

However, Network is a large real converted spec that already uses custom-resource-marked bases and now demonstrates that `resolveArmResources` can produce zero resources for this pattern.

## Expected behavior

We need one of these outcomes:

1. **Spec-side fix path:** If the old Network pattern is considered incorrect, document and enforce the correct pattern. For example, migrate Network to `Azure.ResourceManager.Legacy.CustomAzureResource` or another supported template, and add diagnostics/linter rules/tests to guarantee future converted specs do not use the unsupported pattern.
2. **Library-side fix path:** If converted specs using `@customAzureResource(#{ isAzureResource: true })` should continue to work, then `resolveArmResources` should register/resolve these custom Azure resources so it does not return zero resources for specs like Network.

## Actual behavior

For Network, `resolveArmResources` returns:

```text
resources.length = 0
nonResourceMethods.length = 776
```

This makes the new API unusable as a replacement for legacy resource detection for this spec, and causes a large mismatch against Swagger/legacy resource detection results.

## Why this matters

The .NET management emitter is comparing its legacy detector with `resolveArmResources` as part of migration. Network is the largest mismatch found so far: 140 legacy-only resource ID patterns.

Without a spec-side migration + enforcement plan or a library-side fix, adopting `resolveArmResources` would drop all Network resources.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.