Description
When using @@hierarchyBuilding to change a model's base type to a different model that doesn't contain all the same properties as the original base, properties inherited from the original base are silently dropped from the model instead of being promoted to the model's own properties.
This causes generated SDK code to lose properties that were previously available via inheritance, breaking the API surface.
Repro
Consider a spec like (simplified from Azure Compute):
model UpdateResourceDefinition {
@visibility(Lifecycle.Read) id?: string;
@visibility(Lifecycle.Read) name?: string;
@visibility(Lifecycle.Read) type?: string;
tags?: Record<string>;
}
model GalleryUpdate extends UpdateResourceDefinition {
properties?: GalleryProperties;
identity?: GalleryIdentity;
}
In client.tsp:
#suppress "@azure-tools/typespec-azure-core/no-legacy-usage" "Preserve previous base type"
@@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(GalleryUpdate,
Azure.ResourceManager.Foundations.ProxyResource,
"csharp"
);
Expected behavior
TCGC should output GalleryUpdate with:
baseModel: ProxyResource
properties: [properties, identity, tags] — the tags property should be promoted from the dropped UpdateResourceDefinition base because ProxyResource does not define it.
(id, name, type are correctly omitted because ProxyResource provides them.)
Actual behavior
tspCodeModel.json shows:
{
"name": "GalleryUpdate",
"baseModel": { "$ref": "<ProxyResource>" },
"properties": [
{ "name": "properties", ... },
{ "name": "identity", ... }
]
}
The tags property is missing entirely — it was on the original base (UpdateResourceDefinition) but is not on the new base (ProxyResource), and TCGC drops it instead of promoting it to GalleryUpdate.
Impact
In Azure SDK for .NET Compute migration (Azure/azure-sdk-for-net#58139):
- Pre-existing baseline:
public class GalleryPatch : ResourceData with public IDictionary<string, string> Tags { get; } (inherited from base).
- After applying
@@hierarchyBuilding(GalleryUpdate, ProxyResource, "csharp") to fix the base type, Tags is missing from generated code, breaking ApiCompat with MembersMustExist: Member 'Tags.get()' does not exist.
This affects 9 Gallery patch models in Compute: GalleryPatch, GalleryImagePatch, GalleryImageVersionPatch, GalleryApplicationPatch, GalleryApplicationVersionPatch, GalleryScriptPatch, GalleryScriptVersionPatch, GalleryInVmAccessControlProfilePatch, GalleryInVmAccessControlProfileVersionPatch.
Workaround
Add custom partial class code to re-introduce the missing properties — but this is fragile and duplicates the spec.
Environment
- TCGC version: latest (as of @azure-typespec/http-client-csharp-mgmt emitter package shipped with azure-sdk-for-net main)
- Reproducible with the Compute spec at azure-rest-api-specs commit
bf19852c9f6 on branch compute/add-csharp-client-customizations (ArcturusZhang fork).
Description
When using
@@hierarchyBuildingto change a model's base type to a different model that doesn't contain all the same properties as the original base, properties inherited from the original base are silently dropped from the model instead of being promoted to the model's own properties.This causes generated SDK code to lose properties that were previously available via inheritance, breaking the API surface.
Repro
Consider a spec like (simplified from Azure Compute):
In
client.tsp:Expected behavior
TCGC should output
GalleryUpdatewith:baseModel:ProxyResourceproperties:[properties, identity, tags]— thetagsproperty should be promoted from the droppedUpdateResourceDefinitionbase becauseProxyResourcedoes not define it.(
id,name,typeare correctly omitted becauseProxyResourceprovides them.)Actual behavior
tspCodeModel.jsonshows:{ "name": "GalleryUpdate", "baseModel": { "$ref": "<ProxyResource>" }, "properties": [ { "name": "properties", ... }, { "name": "identity", ... } ] }The
tagsproperty is missing entirely — it was on the original base (UpdateResourceDefinition) but is not on the new base (ProxyResource), and TCGC drops it instead of promoting it toGalleryUpdate.Impact
In Azure SDK for .NET Compute migration (Azure/azure-sdk-for-net#58139):
public class GalleryPatch : ResourceDatawithpublic IDictionary<string, string> Tags { get; }(inherited from base).@@hierarchyBuilding(GalleryUpdate, ProxyResource, "csharp")to fix the base type,Tagsis missing from generated code, breaking ApiCompat withMembersMustExist: Member 'Tags.get()' does not exist.This affects 9 Gallery patch models in Compute: GalleryPatch, GalleryImagePatch, GalleryImageVersionPatch, GalleryApplicationPatch, GalleryApplicationVersionPatch, GalleryScriptPatch, GalleryScriptVersionPatch, GalleryInVmAccessControlProfilePatch, GalleryInVmAccessControlProfileVersionPatch.
Workaround
Add custom partial class code to re-introduce the missing properties — but this is fragile and duplicates the spec.
Environment
bf19852c9f6on branchcompute/add-csharp-client-customizations(ArcturusZhang fork).