Skip to content

Add no-replace-inherited-props linting rule for ARM#4384

Open
Copilot wants to merge 8 commits into
mainfrom
copilot/add-arm-no-replace-inherited-props-linting-rule
Open

Add no-replace-inherited-props linting rule for ARM#4384
Copilot wants to merge 8 commits into
mainfrom
copilot/add-arm-no-replace-inherited-props-linting-rule

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 6, 2026

New ARM linter rule that flags redefining a property already declared on a base model — an Azure API anti-pattern that currently crashes the breaking-change tool (azure-rest-api-specs#42903).

Rule

arm-no-replace-inherited-props walks baseModel ancestry. A redefinition is permitted when either:

  • Identical typeproperty.type === inherited.type. Because aliases share identity and template instantiations are cached, this covers systemData: SystemData (alias) over Foundations.SystemData, the implicit tags: Record<string> cloned by model X is TrackedResource<...>, etc.
  • Same scalar family — both sides reduce to string, numeric, or boolean. Walks baseScalar chains, classifies enum members by value type, reduces unions via getUnionAsEnum from @azure-tools/typespec-azure-core, and unwraps UnionVariants and literals. No special-case needed for ARM name or @discriminator overrides.

Changes

  • packages/typespec-azure-resource-manager/src/rules/arm-no-replace-inherited-props.ts — rule implementation.
  • Registered in src/linter.ts (all ruleset) and enabled in packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts.
  • 18 tests covering: derived-model overrides (warn), and allowed cases for identical type, alias, is TrackedResource tags clone (implicit and explicit), and the full scalar-family matrix (scalar, derived scalar, literal value, closed/open union, named union variant, ARM name, @discriminator literal).
  • Docs: new rule page, regenerated linter.md reference and package README.md.
  • Changeset under .chronus/changes/ for @azure-tools/typespec-azure-resource-manager and @azure-tools/typespec-azure-rulesets.

Example

@armProviderNamespace
namespace MyService;

@discriminator("kind")
model Pet {
  kind: string;
  weight: int32;
}

model Cat extends Pet {
  kind: "cat";    // OK — same scalar family (string)
  weight: int32;  // OK — same scalar family (numeric)
}

model FooProperties { p: string; }
model FooResource is TrackedResource<FooProperties> {
  ...ResourceNameParameter<FooResource>;
  tags?: Record<string>;  // OK — identical type to inherited tags
}

model InnerBase { a: string; }
model InnerDerived extends InnerBase { b: string; }
model Base { nested: InnerBase; }
model Child extends Base {
  nested: InnerDerived;  // ⚠ arm-no-replace-inherited-props
}

@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 labels May 6, 2026
Copilot AI changed the title [WIP] Add ARM linting rule to prevent repeating inherited properties Add arm-no-replace-inherited-props linting rule May 6, 2026
Copilot AI requested a review from markcowl May 6, 2026 02:29
Copy link
Copy Markdown
Member

@markcowl markcowl left a comment

Choose a reason for hiding this comment

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

There is a merge conflict. Pull the latest from main, resolve the conflict, ensure all properties are correctly formatted and all tests pass and that only the chnages associated with this PR are in the PR diff

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 7, 2026

There is a merge conflict. Pull the latest from main, resolve the conflict, ensure all properties are correctly formatted and all tests pass and that only the chnages associated with this PR are in ...

Merged latest main and resolved the conflict in the auto-generated website/.../reference/linter.md (took main's link-format change and re-ran regen-docs to add the new rule entry). Also enabled the new rule in packages/typespec-azure-rulesets/src/rulesets/resource-manager.ts. Verified git diff origin/main shows only the 8 files associated with this PR. Targeted tests pass (147 ARM rule tests + 3 rulesets tests) and pnpm format is clean. Done in 49acb48.

Copilot AI requested a review from markcowl May 7, 2026 19:27
@markcowl markcowl added the int:azure-specs Run integration tests against azure-rest-api-specs label May 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

⚡ Benchmark Results

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

Metric Baseline Current Change
 ↳ emit/@azure-tools/typespec-autorest 🟢 166.1ms 🟢 193.6ms +16.5% 🔴
Full details – comparing 792e97a vs baseline 8cd8304
Metric Baseline Current Change
total 🔴 6.59s 🔴 6.51s -1.3%
loader 🟡 212.7ms 🟢 177.6ms -16.5% 🟢
resolver 🟢 20.3ms 🟢 16.4ms -18.8% 🟢
checker 🟢 187.3ms 🟢 183.5ms -2.0%
validation 🟢 43.4ms 🟢 43.3ms -0.1%
 ↳ validation/@azure-tools/typespec-azure-core 🟢 6.2ms 🟢 6.5ms +4.7%
 ↳ validation/@typespec/http 🟢 5.4ms 🟢 5.6ms +4.1%
 ↳ validation/@typespec/rest 🟢 0.6ms 🟢 0.6ms -8.0%
 ↳ validation/@typespec/versioning 🔴 28.4ms 🔴 29.3ms +3.1%
 ↳ validation/compiler 🟢 1.8ms 🟢 1.4ms -23.8%
linter 🟡 212.3ms 🟢 130.8ms -38.4% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/auth-required 🟢 0.0ms 🟢 0.0ms +4.1%
 ↳ linter/@azure-tools/typespec-azure-core/bad-record-type 🟢 0.4ms 🟢 0.3ms -40.5%
 ↳ linter/@azure-tools/typespec-azure-core/byos 🟢 9.0ms 🟢 5.5ms -38.4% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/casing-style 🟢 0.8ms 🟢 0.6ms -23.7%
 ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance 🟢 0.1ms 🟢 0.1ms -1.5%
 ↳ linter/@azure-tools/typespec-azure-core/documentation-required 🟢 0.9ms 🟢 0.8ms -11.3%
 ↳ linter/@azure-tools/typespec-azure-core/friendly-name 🟢 0.8ms 🟢 0.6ms -13.7%
 ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required 🟢 0.2ms 🟢 0.2ms +0.9%
 ↳ linter/@azure-tools/typespec-azure-core/known-encoding 🟢 0.3ms 🟢 0.3ms +0.0%
 ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required 🟢 0.3ms 🟢 0.3ms -10.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch 🟢 0.2ms 🟢 0.2ms -4.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union 🟢 0.3ms 🟢 0.2ms -7.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-enum 🟢 0.0ms 🟢 0.0ms +3.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes 🟢 0.1ms 🟢 0.1ms -8.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops 🟢 0.1ms 🟢 0.1ms -6.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-format 🟢 0.9ms 🟢 0.6ms -25.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric 🟢 0.4ms 🟢 0.4ms -13.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 31.4ms 🟡 18.6ms -40.8% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage 🟢 1.1ms 🟢 1.1ms -4.7%
 ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator 🟢 0.1ms 🟢 0.1ms -0.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-nullable 🟢 0.3ms 🟢 0.3ms -1.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime 🟢 1.2ms 🟢 1.1ms -5.1%
 ↳ linter/@azure-tools/typespec-azure-core/no-openapi 🟢 3.0ms 🟢 2.1ms -31.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-private-usage 🟢 2.1ms 🟢 1.9ms -10.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 31.3ms 🟡 19.6ms -37.6% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-response-body 🔴 43.5ms 🔴 24.4ms -44.0% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟢 0.0ms 🟢 0.0ms -11.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch 🟢 7.8ms 🟢 4.7ms -39.7% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params 🟢 0.3ms 🟢 0.2ms -35.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator 🟢 0.0ms 🟢 0.0ms -8.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-unknown 🟢 0.3ms 🟢 0.2ms -35.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union 🟢 0.4ms 🟢 0.4ms +5.2%
 ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version 🟢 0.2ms 🟢 0.2ms +1.3%
 ↳ linter/@azure-tools/typespec-azure-core/request-body-problem 🟢 0.3ms 🟢 0.3ms -18.7%
 ↳ linter/@azure-tools/typespec-azure-core/require-versioned 🟢 0.0ms 🟢 0.0ms -13.7%
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 38.2ms 🔴 22.0ms -42.5% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body 🟢 0.4ms 🟢 0.3ms -28.8%
 ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model 🟢 0.3ms 🟢 0.3ms -1.1%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-names 🟡 10.2ms 🟢 4.9ms -52.2% 🟢
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations 🟢 0.1ms 🟢 0.1ms -9.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🟢 3.7ms 🟢 3.8ms +1.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key 🟢 0.1ms 🟢 0.1ms +2.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage 🟢 0.1ms 🟢 0.1ms -7.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 4.6ms 🟢 4.8ms +5.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🟢 4.0ms 🟢 4.4ms +9.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 0.4ms 🟢 0.4ms +3.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes 🟢 0.4ms 🟢 0.5ms +14.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes 🟢 0.0ms 🟢 0.0ms +23.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment 🟢 0.2ms 🟢 0.3ms +15.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property 🟢 0.1ms 🟢 0.1ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator 🟢 0.0ms 🟢 0.0ms -12.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb 🟢 0.1ms 🟢 0.1ms +6.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property 🟢 0.1ms 🟢 0.1ms +5.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format 🟢 0.0ms 🟢 0.0ms -0.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars 🟢 0.2ms 🟢 0.2ms -2.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern 🟢 0.0ms 🟢 0.0ms +4.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation 🟢 0.2ms 🟢 0.2ms -1.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🟢 4.4ms 🟢 4.3ms -1.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch 🟢 0.3ms 🟢 0.3ms +22.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars 🟢 0.2ms 🟢 0.2ms +4.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state 🟢 0.1ms 🟢 0.1ms +6.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels 🟢 0.1ms 🟢 0.1ms -3.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties 🟢 0.1ms 🟢 0.1ms +6.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation 🟢 0.0ms 🟢 0.0ms +12.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 12.3ms 🟡 12.9ms +5.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint 🟢 0.0ms 🟢 0.0ms +8.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers 🟢 0.3ms 🟢 0.3ms -0.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model 🟢 0.1ms 🟢 0.1ms +0.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-replace-inherited-props 🟢 0.0ms 🟢 0.1ms +100.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation 🟢 0.2ms 🟢 0.2ms -3.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🟡 19.7ms 🟡 19.7ms -0.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope 🟢 0.1ms 🟢 0.1ms -9.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name 🟢 0.1ms 🟢 0.1ms +1.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop 🟢 2.4ms 🟢 2.2ms -10.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type 🟢 0.4ms 🟢 0.3ms -5.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression 🟢 0.0ms 🟢 0.0ms +3.6%
 ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict 🟢 1.2ms 🟢 1.0ms -12.9%
 ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix 🟢 0.2ms 🟢 0.2ms -8.6%
emit 🔴 5.83s 🔴 5.87s +0.6%
 ↳ emit/@azure-tools/typespec-autorest 🟢 166.1ms 🟢 193.6ms +16.5% 🔴
 ↳ emit/@azure-tools/typespec-python 🔴 4.33s 🔴 4.29s -0.8%
 ↳ emit/@typespec/http-client-js 🔴 1.14s 🔴 1.16s +1.9%
 ↳ emit/@typespec/openapi3 🟢 147.1ms 🟢 146.9ms -0.2%
 ↳ emit/@typespec/openapi3/compute 🟢 130.7ms 🟢 129.5ms -0.9%
 ↳ emit/@typespec/openapi3/write 🟢 16.9ms 🟢 17.5ms +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)

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 7, 2026

Open in StackBlitz

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

commit: ffad4ac

Copy link
Copy Markdown
Member

@markcowl markcowl left a comment

Choose a reason for hiding this comment

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

Update the changeset to include your change to the rulesets.

Pull the latest from main, ensure all files are well formatted and only the changes associated with this PR are in the PR diff.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 7, 2026

Update the changeset to include your change to the rulesets.

Pull the latest from main, ensure all files are well formatted and only the changes associated with this PR are in the PR diff.

Updated the changeset to include @azure-tools/typespec-azure-rulesets (6d60f84). Also pulled latest from main (clean merge, no conflicts) and verified pnpm format is clean. git diff origin/main --stat shows only the 8 files associated with this PR.

Copilot AI requested a review from markcowl May 7, 2026 22:00
Copy link
Copy Markdown
Member

@markcowl markcowl left a comment

Choose a reason for hiding this comment

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

@copilot Please follow the instuctio0ns in the comment

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot Please follow the instuctio0ns in the comment

Done — addressed the review feedback in 5180f69. Details in the inline reply.

Copilot AI requested a review from markcowl May 13, 2026 00:11
Copilot AI requested a review from markcowl May 29, 2026 22:05
@markcowl markcowl marked this pull request as ready for review May 29, 2026 22:32
markcowl added a commit to Azure/azure-rest-api-specs that referenced this pull request Jun 1, 2026
…ity/SecuritySolutionsAPI

Add #suppress directives for the new arm-no-replace-inherited-props linter rule
on three models (CefExternalSecuritySolution, AtaExternalSecuritySolution,
AadExternalSecuritySolution) that intentionally redefine the 'properties' field
with a more specific type.

Related: Azure/typespec-azure#4384

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@markcowl
Copy link
Copy Markdown
Member

markcowl commented Jun 1, 2026

Suppression PR for the Microsoft.Security/SecuritySolutionsAPI violations: Azure/azure-rest-api-specs#43657

Copilot AI and others added 7 commits June 1, 2026 13:11
Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@markcowl markcowl force-pushed the copilot/add-arm-no-replace-inherited-props-linting-rule branch from 2215445 to 6883fa5 Compare June 1, 2026 20:39
markcowl added a commit to Azure/azure-rest-api-specs that referenced this pull request Jun 1, 2026
…ity/SecuritySolutionsAPI

Add #suppress directives for the new arm-no-replace-inherited-props linter rule
on three models (CefExternalSecuritySolution, AtaExternalSecuritySolution,
AadExternalSecuritySolution) that intentionally redefine the 'properties' field
with a more specific type.

Related: Azure/typespec-azure#4384

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

@markcowl markcowl left a comment

Choose a reason for hiding this comment

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

Please pull the latest from main, make the rename suggested in the review comments, validate correct build and rebuild documents, validate that all files are correctly formatted and only changes associated with thsi pr are in the pr diff.

Comment thread packages/typespec-azure-resource-manager/src/rules/no-replace-inherited-props.ts Outdated
Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com>
Copilot AI requested a review from markcowl June 1, 2026 21:06
@markcowl markcowl changed the title Add arm-no-replace-inherited-props linting rule Add no-replace-inherited-props linting rule for ARM Jun 1, 2026
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 meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[linting-rules]: Disallow repeating inherited properties in child types

3 participants