Skip to content

[Swagger Linter Migration] DescriptionMustNotBeNodeName + DescriptiveDescriptionRequired -> documentation-required - #5663

Open
Yuchao Yan (msyyc) wants to merge 23 commits into
mainfrom
promote-lintdiff-description-must-not-be-node-name
Open

Yuchao Yan (msyyc) wants to merge 23 commits into
mainfrom
promote-lintdiff-description-must-not-be-node-name

Conversation

@msyyc

@msyyc Yuchao Yan (msyyc) commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Consolidate DescriptionMustNotBeNodeName and DescriptiveDescriptionRequired into the existing @azure-tools/typespec-azure-core/documentation-required rule. This absorbs #5674 without introducing separate public rule IDs.

The October 22 review fixes simplify the implementation, tests, and published guidance:

  • Keep rule-only types, messages, normalization, and name selection in require-docs.ts; remove the two helper modules.
  • Use the pinned compiler's native enumMember callback, preserving existing missing-doc exemptions and explicit-documentation checks on exempt members.
  • Compare ordinary properties with their authored TypeSpec names, not JSON serialization names. HTTP parameters and multipart parts retain their distinct HTTP naming policy.
  • Reduce the canonical suite from 79 to 32 tests, retaining distinct semantic branches, exact authored targets, missing/blank/name/verb deduplication, and meaningful compliant controls. Reuse one file-level tester and hook.
  • Use standard rule documentation with description, Impact, examples, and Suppression; keep migration history here rather than in the public rule guide.
  • Classify the existing Azure Core changeset as a feature, with a short warning example. Separate sample-package release coverage is retained.

Behavior and legacy mapping

Legacy Swagger linter Native coverage
SummaryOrDescription Existing missing-documentation requirements, scopes, and exemptions remain unchanged.
DescriptionMustNotBeNodeName Reject repeated names and placeholder description, ignoring surrounding whitespace, periods, and case. Operations compare both authored names and effective HTTP verbs.
DescriptiveDescriptionRequired Reject explicitly empty/whitespace-only documentation, including compiler-exposed docs on exempt declarations.

HTTP path/query/header properties use wire names; multipart properties use authored part names with source-name fallback, including repeated parts. Enum members and named union variants use names; unnamed string variants use values. Status-code properties are exempt from name comparisons, not blank checks. Namespaces, interfaces, scalars, inline properties, and otherwise exempt declarations receive explicit-documentation checks without newly requiring absent documentation. Uninstantiated template docs unavailable from the compiler remain outside coverage.

Native-policy adaptation: ordinary properties deliberately use authored names even when @encodedName("application/json", ...) differs. This replaces the previous JSON-name comparison following review; it is not exact Swagger emitted-name parity. One renamed-property regression proves the new source-name behavior; the prior JSON-precedence matrix is removed. The immutable lintdiff sources below are unchanged.

The already-enabled data-plane and resource-manager rulesets intentionally acquire stronger documentation-quality checks. This is not a disabled-by-default opt-in migration. Compiler metadata and emitted Swagger occurrences differ; exact diagnostic population parity and the legacy truthy selector's empty-string discrepancy are not reproduced.

Consolidation and provenance

Check Immutable reviewed lintdiff source Incorporated promotion
DescriptionMustNotBeNodeName #5662 at 3753a319 #5663, including 105eb1be8's sample CI fix.
DescriptiveDescriptionRequired #5672 at 72ab2239 #5674 at 8a3c53e2c.

Merge e4e52dac5 preserves both histories. #5674 is superseded; its branch/history and review threads are retained. The existing PR title follows the combined-migration convention used in #5294 and #5423.

Current local validation (October 22, 2026)

  • mise exec -- pnpm -r --filter "@azure-tools/typespec-azure-rulesets..." build: passed, including Azure Core, ARM, and their dependency closure.
  • mise exec -- pnpm test --pool=threads --maxWorkers=1 --project=@azure-tools/typespec-azure-core --project=@azure-tools/typespec-azure-rulesets: 60 files passed, 522 tests passed, 2 existing skips. The canonical documentation suite has 32 cases.
  • Strict focused TypeScript check of test/rules/require-docs.test.ts using tsc --noEmit --ignoreConfig --module NodeNext --moduleResolution NodeNext --target esnext --strict --skipLibCheck --verbatimModuleSyntax true --types node: passed. The earlier undefined-location errors in this suite are eliminated. Full package test-project type-check is not clean: unchanged casing-style/type-only-import tests and Vitest project boundaries still report errors.
  • Root pnpm format and pnpm lint, scoped CSpell, chronus status, and git diff --check: passed.
  • One-time validation of all four actual published snippets, using compiler createTester with libraries: [], no imports/usings/wrapper, and the real linter: incorrect snippets produce 2 / 2 / 1 diagnostics; correct snippet produces zero. Document SHA-256: e6405852d08b4128d365c582840dbbd3e923b31200e25539ba91969e488534d6. This is a one-time receipt, not continuous Markdown coverage; no per-rule Markdown parser was added.
  • Initial ruleset test failure came from stale ARM build output and passed after rebuilding. Missing locked JavaScript dependencies were restored; the install's unrelated Python prepare hook failed fetching PyPI metadata, but the affected dependency-closure build and tests subsequently passed. No manifests, lockfile, compiler pin, or Python files changed.

These are local results, not a claim of GitHub CI success or merge approval. Final-head CI is inspected separately without waiting for completion. Historical validation counts and behavior claims below are superseded by this section.

Historical PR description and earlier validation (superseded above)

Focused test cleanup (October 21, 2026)

b5ade3c56 removes one redundant unfiltered documentation-rule case while retaining the broader mixed missing/blank/punctuation/name/verb regression. No production behavior, public documentation, or enablement changed, and existing release-note coverage is unchanged.

The canonical suite passed 79/79 cases using the existing threads/single-worker profile with unchanged timeouts. An initial run hit a 10-second setup-hook timeout; its cause is unproven. The package/dependency-closure build and root formatting/lint passed. Focused strict TypeScript checking has the same nine pre-existing undefined-location errors as the exact-head baseline, shifted only by the deleted test; no new errors were introduced. The full test project is not claimed error-free. Earlier counts below are historical.

Summary

Consolidate DescriptionMustNotBeNodeName and DescriptiveDescriptionRequired into the existing @azure-tools/typespec-azure-core/documentation-required rule. This PR absorbs #5674, including its implementation and regression coverage, rather than adding separate no-uninformative-doc or no-empty-doc public rules.

Implemented in merge commit e4e52dac5, preserving the histories of both promotion branches.

This follows the combined-migration presentation used in #5294 and #5423. Further review of both documentation-quality checks should continue here. Closing #5674 as superseded does not imply CI or review approval; its branch and review history are retained, and existing review threads are not resolved by this consolidation.

Combined behavior and legacy-rule mapping

Legacy Swagger linter Native coverage
SummaryOrDescription Existing missing-documentation requirements for types, operations, and members, with their existing scopes and exemptions retained.
DescriptionMustNotBeNodeName Reject explicit descriptions that repeat effective names or the placeholder description, ignoring surrounding whitespace, periods, and case. Operations are checked against both source names and effective HTTP verbs.
DescriptiveDescriptionRequired Reject explicitly empty or whitespace-only documentation, including compiler-exposed documentation on declarations exempt from missing-doc requirements.
  • HTTP path/query/header properties use wire names; ordinary properties use JSON encoded names; multipart properties use authored part names with source-name fallback.
  • Enum members and named union variants use member names; unnamed string variants use their values. HTTP status-code properties are exempt from name comparisons, not explicit blank-documentation checks.
  • Blank checks also cover namespaces, interfaces, scalars, inline properties, union variants, and explicitly documented declarations exempt from missing-doc requirements. Uninstantiated template documentation unavailable from the compiler remains outside coverage.
  • Absent documentation is not newly required on exempt declarations. Required targets receive one blank diagnostic, not duplicate findings from the combined validators.
  • The existing data-plane and resource-manager rulesets already enable documentation-required. This intentionally strengthens documentation quality for existing users; it is not a disabled-by-default opt-in migration.

The native contract uses compiler documentation metadata, not emitted Swagger summary/description occurrences. The legacy truthy selector's empty-string discrepancy is intentionally not reproduced, and exact emitted diagnostic parity is not claimed.

Consolidation and provenance

Check Immutable reviewed lintdiff source Separate promotion incorporated here
DescriptionMustNotBeNodeName #5662 at 3753a319 #5663 at 105eb1be8, including the sample CI fix.
DescriptiveDescriptionRequired #5672 at 72ab2239 #5674 at 8a3c53e2c.

The source lintdiff implementations are unchanged. Explicit-documentation checks run directly from the existing native semantic callbacks; one quality-check helper preserves the broader authored-documentation scope and the missing-doc exemptions without listener remapping or validator factories. The combined tests now expect name-only and placeholder descriptions to produce uninformative, not empty, findings; an unfiltered regression verifies the combined rule reports blank and uninformative documentation together.

The user-facing rule documentation has one combined legacy-coverage table, and Azure Core has one consolidated fix changelog entry. Widget Manager colors and the ARM library provisioning state have meaningful descriptions, with their OpenAPI snapshots regenerated.

Validation recorded at consolidation (historical)

  • Reproduced the merged test conflict before correcting the expectations.
  • Combined documentation suites: 85 passed.
  • Full affected-package run: 62 files passed; 576 tests passed and 2 existing skips, covering Azure Core, Azure rulesets, sample snapshots, and playground samples.
  • Full monorepo build, including the website and engineering type-check: passed.
  • Full repository lint and formatting: passed.
  • Chronus status and diff hygiene: passed.

These are local results, not a claim that fresh GitHub CI or review has completed. The separate REST API Specs integration check has adoption failures from strengthening an already-enabled rule; no downstream specification changes or diagnostic suppressions are included here.

Historical #5663 promotion notes before consolidation (superseded where noted above)

Current implementation after review

Uninformative-documentation checks are consolidated into existing documentation-required. Operations are compared against both their source name and HTTP verb; emitted-name, multipart and member behavior is retained. Existing missing-doc exemptions remain unchanged. The separate opt-in rule is removed: this intentionally strengthens documentation quality. Compatibility with the matching #5674 consolidation was verified.

Implemented in 5e8dc5927. Review threads are left unresolved.

Historical promotion notes and earlier validation (superseded where noted above)

Summary

Promote Swagger DescriptionMustNotBeNodeName to @azure-tools/typespec-azure-core/no-uninformative-doc.

The rule warns when explicit documentation repeats the name it describes or uses the placeholder description. It is registered in Azure Core and explicitly disabled by default in both the data-plane and resource-manager rulesets, so existing specs do not acquire new warnings automatically.

This PR includes the native rule, regression tests, documentation, generated linter references, ruleset registration, and separate Chronus entries for the Core feature and internal ruleset registration.

Original Swagger linter

The legacy rule recursively examines objects containing string descriptions. It trims whitespace, removes periods, and compares case-insensitively against an explicit name or the object's path key; it also rejects the placeholder description. Its executable registration is ARM.

Source TypeSpec lintdiff rule

Item Value
Development PR #5662
Local rule description-must-not-be-node-name
Immutable reviewed source 3753a319f32f3926005536029f9ff32b94f3c905
Source implementation description-must-not-be-node-name.ts
Migration evidence migration.md

The promoted create(context) implementation and normalization function are identical to the reviewed source. Promotion changes the public rule/export name, documentation metadata, package registration, native testing setup, and rulesets. The source was not modified during promotion.

Destination analysis

Azure Core owns this shared documentation-quality concern: the implementation uses compiler and HTTP APIs, without ARM resource metadata or SDK-name overrides. Core's existing documentation-required rule checks missing documentation, not repetitive or placeholder text. ARM would unnecessarily restrict the native rule's audience; TCGC is not appropriate because this is not an SDK-naming policy.

How the promoted TypeSpec linter works

  • Reads explicit @doc text and doc comments through compiler getDoc; normalizes surrounding whitespace, periods, and case.
  • Checks named models, scalars, enums, unions, enum members, properties, union variants, and operations.
  • Compares path/query/header properties against HTTP wire names. Ordinary non-part properties use JSON encoded names, falling back to source names.
  • Compares multipart properties against authored HttpPart names, including repeated-part arrays. Unnamed parts use the source property name; JSON encoding does not rename multipart parts.
  • Compares operations against their effective HTTP verb, including inferred GET and POST. HTTP resolution diagnostics remain owned by HTTP validation.
  • Compares named union variants against their names and unnamed string variants against their literal values. Other unnamed variants are checked only for placeholder text.
  • Ignores missing or normalized-empty documentation and status-code properties. Key properties are not exempt. Diagnostics target authored semantic declarations.

For example, @doc("Ready") Ready: "available" warns, while @doc("available") Ready: "available" does not.

The production rule does not emit or read Swagger, predict generated schema names, project API versions, or add emitter, OpenAPI, ARM, or TCGC dependencies.

Fixture-to-native test mapping

All 15 source fixtures are represented in the 40 native test cases. Source fixtures are pinned under DescriptionMustNotBeNodeName; native tests exercise the compiler/HTTP predicates directly rather than copying snapshots or ARM template scaffolding.

Source fixture(s) Native coverage
description-matches-name Property-name equality and placeholder text
descriptive-docs Meaningful documentation
literal-description Placeholder normalization
model-description-matches-model-name Model-name equality; whitespace, periods, and case
operation-description-matches-http-verb Explicit HTTP verbs
operation-description-matches-typespec-name-only Source-operation-name compliance
parameter-description-matches-emitted-name, parameter-description-matches-source-name-only HTTP wire names and source-name-only controls
property-description-matches-property-name Ordinary property-name equality
member-and-key-documentation Enum/union member names versus literal values; key properties
inferred-http-verbs Effective inferred GET/POST and explicit-verb precedence
json-encoded-property, json-encoded-source-name-only JSON names and source-name-only compliance
multipart-authored-names, multipart-source-name-only Direct/custom/array/repeated parts; authored names and compliant controls

Additional native coverage includes scalar/enum/union names, doc comments, query/header metadata, unnamed variants, missing/empty docs, status-code exemption, exact diagnostic locations, multipart JSON-name isolation, and both published documentation examples.

Migration evidence

The source validation passed 47 native tests, 15 strict fixtures, and five affected fixture groups. The final full corpus run attempted 468 projects, successfully compiled 462, and retained six documented compilation exclusions. The final target-rule diagnostic multiset was unchanged at 8,499; generated corpus outputs were restored and are not included in this PR.

The pinned migration note records project overlap, selected-version attribution, one-sided findings, outliers, and limitations. Swagger counts emitted occurrences; TypeSpec diagnostics describe authored semantic declarations and instances. Repeated roots/versions, inline copies, qualified schema names, compatibility or unused types, version selection, and constant route parameters explain population differences.

The native documentation-quality contract is covered. Corpus overlap and counts are not proof of arbitrary executable Swagger parity.

Validation and review

Required promotion checks passed:

  • 40 focused native tests, including incorrect/correct documentation examples.
  • Full Azure Core suite: 474 passed, 2 existing skips across 58 test files.
  • 6 rulesets tests, including disabled-by-default registration.
  • Dependency-closure/package builds, package lint, scoped formatting, and diff hygiene.
  • Documentation regeneration and formatting of authored/generated guidance.
  • Chronus status for the Core feature and internal ruleset-registration entries.

The two existing skips are the unrelated @example and @useRef groups in no-openapi.test.ts. Documentation regeneration retains existing missing-diagnostic-documentation warnings outside this rule. No new tests are skipped. A website build/full-repository wrapper was not part of the targeted promotion checks.

Fresh independent local reviews were clean. The final source review completed after 2 Balanced Copilot rounds at 3753a319; the final promotion review completed after 1 Balanced round at 2c5214be. Independent refetches confirmed zero review-specific comments and zero unresolved Copilot threads on both final heads. The inferred-verb, JSON-name, and multipart findings are implemented and resolved.

Promotion sync policy

Source semantics remain immutable during promotion. Any future confirmed source-semantic defect must be repaired and reviewed in lintdiff first, then promoted from that exact reviewed commit; it must not be fixed only in the official copy.

heavy

Historical #5674 promotion notes before consolidation (superseded where noted above)

Current implementation after review

Empty/whitespace explicit documentation is checked by existing documentation-required, preserving its missing-doc exemptions. The separate no-empty-doc rule/registration is removed and semantic coverage is transferred. This intentionally strengthens documentation quality. Compatibility with the matching #5663 consolidation was verified.

Implemented in 20683492f. Review threads are left unresolved.

Historical promotion notes and earlier validation (superseded where noted above)

Original Swagger linter

The original rule:

  • Selects description fields in unresolved OpenAPI 2 documents.
  • Ignores null and non-string inputs in its function.
  • Reports selected strings whose trim() result is empty, at their selected JSON paths.
  • Accepts nonblank text without judging prose quality.

How the Swagger linter works

Spectral recursively selects objects using $..[?(@object() && @.description)].description, then applies the blank-string check. This truthy selector skips missing, empty-string, null, and numeric descriptions before the function runs; whitespace strings are selected and rejected. That executable discrepancy is not copied into the native rule. Emitted occurrences and semantic TypeSpec declarations are different diagnostic populations, so exact Swagger diagnostic parity is intentionally partial.

Source TypeSpec lintdiff rule

  • Validator ID: DescriptiveDescriptionRequired.
  • Local rule: descriptive-description-required.
  • Canonical validator slug: descriptive-description-required.
  • Source repository: Azure/typespec-azure; source draft #5672.
  • Source branch: lintdiff-descriptive-description-required.
  • Immutable, cleanly reviewed and pushed source commit: 72ab22394704fce1a1555c879ff7335da8debf42.
  • Source worktree: C:\dev\worktrees\lintdiff-descriptive-description-required, clean at the pinned source head.
  • Original lintdiff source rule.

The source rule was assumed done for this promotion invocation. It was not modified during promotion. The development review completed two rounds with no new comments at the pinned head. The earlier development publication commit was 2423e379680a19091a1b86ffd5c240daa3d4089e; the reviewed source includes subsequent test/evidence fixes without changing production rule behavior.

Destination analysis

The agent selected @azure-tools/typespec-azure-core: the rule uses compiler documentation metadata only, applies to both ARM and data-plane authoring, and needs neither ARM resource semantics nor SDK-name resolution. ARM would unnecessarily narrow a shared authoring requirement; TCGC is not appropriate because this is not a generated SDK API policy. No ARM or TCGC dependency is introduced.

Core's existing documentation-required addresses missing documentation and tests documentation truthiness. It does not reject nonempty whitespace strings and has a different declaration scope. This rule complements that policy rather than duplicating it.

How the promoted TypeSpec linter works

The official rule is @azure-tools/typespec-azure-core/no-empty-doc.

It reads getDoc(program, target) on namespaces, interfaces, operations, models, model properties, scalars, enums, enum members, unions, and union variants. Undefined documentation is compliant; defined documentation with an empty trimmed value produces a warning targeted at the offending declaration. Any non-whitespace character is sufficient.

The enum callback explicitly iterates enum.members because the compiler does not dispatch enum-member listener callbacks. Tests preserve exact property and enum-member diagnostic locations. Standard linter traversal owns library filtering; there is no custom HTTP reachability, provider, version/projection, emitted-reference, or OpenAPI-extension filter.

The native rule's create(context) implementation matches the immutable source after line-ending normalization. Promotion adapts only the official name/export, native documentation metadata, and documentation URL. The source's unprojected native authoring population remains unchanged.

The rule is explicitly disabled (false) in both data-plane and resource-manager rulesets. The Core feature change and disabled-only rulesets internal change have separate Chronus entries.

Fixture-to-native test mapping

Snapshots and validator output are evidence only; they were not copied into the official package. Reduced compiler-native snippets exercise the same rule-owned branches.

Original lintdiff fixture Native vitest case Coverage note
empty-description it("rejects a whitespace-only property description") Reduced property snippet; one blank-description diagnostic.
whitespace-param-description it("rejects a whitespace-only parameter description") Direct operation parameter; one diagnostic.
non-empty-description it("accepts nonblank descriptions on models, properties, and operations") Compliant supplied documentation, without emitted snapshots or ambient suppressions.
enum-member-description it("targets offending enum members rather than their containing enum") Whitespace-member branch and precise member targeting.
N/A (review regression) it("targets offending properties rather than their containing model") Two diagnostics with exact property file/position/end.
N/A (review regression) it("targets offending enum members rather than their containing enum") Source-review member-location regression retained.
N/A (native documentation examples) it("validates the documented incorrect and correct examples") Reads the actual authored Markdown examples; incorrect warns and correct is valid with this rule enabled.

The 24 native cases also cover registered declaration kinds, absent and nonblank documentation, empty and Unicode-whitespace content, documentation comments, and diagnostic targeting. Fresh asynchronous tester initialization follows the Core test lifecycle.

Migration evidence

See the checked-in migration.md for focused comparisons, representative and full real-service corpus evidence, one-sided project explanations, compile exclusions, and remaining uncertainty. Those counts describe the immutable source's comparison population, not a fresh official-library corpus run or universal executable equivalence.

Validation recorded at consolidation (historical)

All required targeted checks are complete:

  • Core prerequisite closure and affected package builds.

  • Focused native rule tests: 24 passed, including the actual authored documentation examples.

  • Core package lint.

  • Core documentation regeneration, inspection, and explicit formatting/checking of the README, authored rule, generated linter reference, and ignored generated rule page.

  • Maintained-file formatting check and git diff --check.

  • LF Chronus entries and pnpm chronus status.

  • Rulesets dependency closure/build, package lint, and five tests passed.

  • Full Core native suite: 58 files passed, 458 tests passed, two original skips, 460 total, using the approved package-scoped profile:

    mise exec -- pnpm --filter @azure-tools/typespec-azure-core exec vitest run --pool=threads --maxWorkers=1
    
  • Independent persistent local precommit review of the exact ten-file scope: no significant issues.

Validation limitations

The original full Core run had two per-test 5,000ms timeouts (override-api-version and casing-style); the authorized single-worker diagnostic retained one casing-style timeout. Both failed receipts remain preserved. A coordinator-authorized bounded comparison ran the exact remaining casing test once against the baseline registration and once against the restored draft using threads/single-worker; both passed. The subsequent single authorized full suite passed with the identical 460-test population and the same two original skips.

The original timeout cause is unproven. This is not a claimed environmental diagnosis. Vitest 5, isolate: false, the configured 5,000ms test and 10,000ms hook limits, assertions, dependencies, and skips were unchanged. The passing profile does not grant further retries. Baseline isolation restored the exact draft registration and all 404 archived compiled outputs.

Repository-wide validate:pr and the website build were not run; the required targeted plan above is complete, and CI's dedicated Website job remains authoritative for the Astro build. The generated rule page was inspected/formatted but remains ignored and is not force-added.

Promotion sync policy

The lintdiff source remains immutable during promotion. A confirmed source-semantic defect discovered in promotion review blocks this PR and returns evidence to the owning queue; only that coordinator may authorize a bounded return-to-development repair cycle. This PR would then be refreshed incrementally only after clean source review at a new exact pinned commit, with native regressions and provenance updated. Promotion itself never edits the source rule or silently changes its semantics.

Historical review cleanup (October 19, 2026; superseded below)

Consolidated empty/effective-name behavior into require-docs.test.ts and deleted the two additional behavior files. Authored-documentation filtering stays local; combined/missing-documentation checks remain unfiltered. HTTP metadata spies are scoped to the naming-quality subgroup and restored after each case; diagnostic targets and call-count checks remain. Removed the redundant Core internal entry, retaining the fix and separate samples-package entries.

Published in 57eb47e. Fresh focused validation: 86 tests passed, package production typecheck, root pnpm format, root pnpm lint, and diff hygiene passed. The full test TypeScript project retains pre-existing diagnostics (19 before, 19 after); the exact-head baseline comparison found no new diagnostics, accounting explicitly for moved tests and any removed duplicate fixture. This is not a claim that the full test TypeScript project is error-free or that pending CI has passed. These current file-layout/coverage statements supersede earlier descriptions of the removed test files; historical validation remains historical.

Review cleanup (October 21, 2026)

Implemented selected review IDs 32–36 in 85ac77b. Removed the unreachable uninstantiated-template success case, HTTP resolver spy/call-list oracle, and test-only missing-diagnostic filters. All canonical fixtures now instantiate the shipped public rule with minimally documented scaffolding or assert the real missing-doc warning. Mixed missing/blank/name controls and exact authored targets remain.

Documentation-quality checks now run directly in native callbacks, with explicit enum-member iteration and a small effective-name resolver. Missing-doc exemptions, broader explicit-doc coverage, blank-diagnostic deduplication, public rule ID and existing enablement are unchanged. Added instantiated-model and explicit discriminator regressions. Reduced multipart checks to a normal named part and a focused repeated outer-array part; retained authored/source/JSON precedence, fallback and placeholder controls, and combined path/query/header source-name compliance with JSON-precedence cases.

Fresh local validation: 80 canonical rule tests passed; the complete Azure Core and Azure rulesets run passed 60 files, 568 tests, with 2 existing skips. Azure Core package build (including production TypeScript compilation and TypeSpec library lint), root pnpm format, root pnpm lint, Chronus status and diff hygiene passed. Reused existing production release coverage without adding internal test-history notes. An initial diagnostic-order expectation and an intermediate TypeScript narrowing error were corrected before the passing validation. No compiler timeout settings were changed.

Available final-head CI was inspected once after publication: only license/cla had reported (success); build/test CI was not yet reported. CI pending - not awaited. These local results do not claim fresh CI passed or whole-PR review/merge readiness. The earlier consolidation and promotion validation above remains historical. Existing review threads are untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added int:azure-specs Run integration tests against azure-rest-api-specs lib:azure-core Issues for @azure-tools/typespec-azure-core library meta:website TypeSpec.io updates linter Issues related to linter rules labels Oct 10, 2026
@msyyc
Yuchao Yan (msyyc) requested a balanced review from Copilot October 10, 2026 05:40
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • ✅ @azure-tools/typespec-azure-core
Show changes

@azure-tools/typespec-azure-core - feature ✏️

Strengthen documentation-required to reject explicitly empty or whitespace-only documentation and descriptions that repeat a declaration's name or the placeholder description. Ordinary properties use their authored names, regardless of JSON serialization names; HTTP parameters and multipart parts retain their HTTP names. Explicit-documentation checks also cover namespaces, interfaces, scalars, inline properties, union variants, and declarations exempt from missing-doc requirements when their documentation is exposed by the compiler. Operation descriptions are compared with both the source operation name and effective HTTP verb. Missing-documentation requirements and exemptions are unchanged. The existing data-plane and resource-manager rulesets already enable this rule.,> ,> tsp,> // Warns: the description only repeats the authored name.,> /** Widget */,> model Widget {},>

@azure-tools/typespec-samples - internal ✏️

Update Widget Manager color and ARM library provisioning-state descriptions to satisfy documentation-required, and regenerate sample snapshots.

@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

📦 Package size report

2 packages changed size, +8.05 KB (+0.0%) packed overall.

Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-azure-resource-manager 194.63 KB → 201.90 KB +7.27 KB (+3.7%) 🔴 1.16 MB → 1.21 MB +48.33 KB (+4.1%) 🔴
@azure-tools/typespec-azure-core 136.55 KB → 137.93 KB +1.39 KB (+1.0%) 🔴 733.30 KB → 739.94 KB +6.64 KB (+0.9%) 🔴
12 package(s) with no notable change
Package Packed (base → head) Δ Packed Unpacked (base → head) Δ Unpacked
@azure-tools/typespec-client-generator-core 250.01 KB → 249.45 KB -577 B (-0.2%) 1.33 MB → 1.32 MB -3.79 KB (-0.3%)
@azure-tools/typespec-azure-rulesets 6.00 KB → 5.94 KB -64 B (-1.0%) 35.20 KB → 35.11 KB -88 B (-0.2%)
@azure-tools/typespec-azure-portal-core 36.26 KB → 36.28 KB +17 B (+0.0%) 242.62 KB → 242.88 KB +260 B (+0.1%)
@azure-tools/azure-http-specs 143.53 KB → 143.53 KB — 1.20 MB → 1.20 MB —
@azure-tools/typespec-autorest 87.87 KB → 87.87 KB — 424.17 KB → 424.17 KB —
@azure-tools/typespec-autorest-canonical 7.42 KB → 7.42 KB — 26.00 KB → 26.00 KB —
@azure-tools/typespec-azure-examples 80.15 KB → 80.15 KB — 383.36 KB → 383.36 KB —
@azure-tools/typespec-go 264.28 KB → 264.28 KB — 1.35 MB → 1.35 MB —
@azure-tools/typespec-java 20.22 MB → 20.22 MB — 22.52 MB → 22.52 MB —
@azure-tools/typespec-metadata 15.88 KB → 15.88 KB — 62.08 KB → 62.08 KB —
@azure-tools/typespec-python 42.58 KB → 42.58 KB — 166.02 KB → 166.02 KB —
@azure-tools/typespec-ts 550.66 KB → 550.66 KB — 2.75 MB → 2.75 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.

@pkg-pr-new

pkg-pr-new Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@azure-tools/typespec-azure-core@5663
npm i https://pkg.pr.new/@azure-tools/typespec-azure-rulesets@5663

commit: e00571b

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Inferred HTTP verbs and encoded property names currently escape checks performed by the legacy validator.

2 open findings
What changed in this PR

Adds an opt-in Azure Core lint rule migrating DescriptionMustNotBeNodeName.

Changes:

  • Implements and tests uninformative-documentation detection.
  • Registers the rule disabled by default in both Azure rulesets.
  • Adds documentation and Chronus entries.
File Description
website/​.../​reference/​linter.md Lists the rule.
packages/​typespec-azure-rulesets/​test/​validate-rules-defined.test.ts Verifies opt-in status.
packages/​typespec-azure-rulesets/​src/​rulesets/​resource-manager.ts Registers disabled rule.
packages/​typespec-azure-rulesets/​src/​rulesets/​data-plane.ts Registers disabled rule.
packages/​typespec-azure-core/​test/​rules/​no-uninformative-doc.test.ts Adds rule tests.
packages/​typespec-azure-core/​src/​rules/​no-uninformative-doc.ts Implements the rule.
packages/​typespec-azure-core/​src/​rules/​no-uninformative-doc.md Documents behavior.
packages/​typespec-azure-core/​src/​linter.ts Exports the rule.
packages/​typespec-azure-core/​README.md Lists the rule.
.chronus/​changes/​register-no-uninformative-doc-2026-10-10.md Describes ruleset registration.
.chronus/​changes/​no-uninformative-doc-2026-10-10.md Describes the Core feature.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/typespec-azure-core/src/rules/no-uninformative-doc.ts Outdated
Comment thread packages/typespec-azure-core/src/rules/no-uninformative-doc.ts Outdated
@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Renamed multipart parameters bypass the intended uninformative-documentation check.

1 open finding
2 resolved since last review

🧠 Review effort: Balanced

Comment thread packages/typespec-azure-core/src/rules/no-uninformative-doc.ts Outdated
Resolve authored and default HTTP part names independently of JSON naming, preserve repeated-part metadata and port reviewed native regressions.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation, registration, documentation, release metadata, and regression coverage are complete and consistent.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

Yuchao Yan (msyyc) added a commit that referenced this pull request Oct 12, 2026
## Original Swagger linter

- linter code:
[DescriptionMustNotBeNodeName](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/native/legacyRules/DescriptionMustNotBeNodeName.ts)
- linter doc:
[description-must-not-be-node-name.md](https://github.com/Azure/azure-openapi-validator/blob/main/docs/description-must-not-be-node-name.md)

Specific checks:

- [x] Select objects containing a `description` field recursively.
- [x] Ignore non-string descriptions.
- [x] Normalize description/name text by trimming whitespace, removing
periods, and lowercasing.
- [x] Reject a description matching an explicit string `name`.
- [x] Otherwise reject a description matching the containing node's
string path key.
- [x] Otherwise reject the literal placeholder `description`.
- [x] Report at the offending `description` field.

## How the Swagger linter works

The legacy ARM rule recursively selects description-bearing Swagger
objects and compares their text with an explicit name or the object's
path key. Consequently it can inspect schema/property names, HTTP verbs,
parameters, and `x-ms-enum.values` metadata. It emits at most one
finding per selected object using the ordered conditions above. Its
executable ARM registration is the audience source of truth despite the
documentation's broader applicability wording.

The validator counts emitted occurrences, not unique authored
declarations. SQL's repeated root files and AlertsManagement's inline
parameter copies therefore multiply findings. Generated or qualified
schema names, client compatibility types, unused source declarations,
and literal route parameters also make output nodes differ from editable
TypeSpec targets. Those differences are investigated rather than
recreated through emitter-dependent production logic.

## How the migrated TypeSpec linter works

Mapping: `DescriptionMustNotBeNodeName` →
`tsp-lintdiff-local-linter/description-must-not-be-node-name`.

The native rule checks explicit documentation obtained through compiler
`getDoc` on named models, scalars, enums, unions, enum members, union
variants, model properties, and operations. HTTP path/query/header names
take precedence over compiler-resolved ordinary JSON property names.
`getHttpOperation` supplies the effective operation verb, including
inferred GET without a body and POST with a body. Missing or
normalized-empty documentation remains outside this rule; status-code
properties remain exempt.

Earlier changes closed missing enum-member/union-variant checks and
removed the blanket key-property exemption. Enum members are iterated
from the enum listener, following official `documentation-required`
prior art because the installed compiler walker does not dispatch
enum-member events. Named union variants compare their name; unnamed
string variants compare their literal value, while other unnamed
variants are checked only for placeholder text.

Cycle1 repairs two additional native semantic omissions confirmed during
[promotion
review](#5663 (review)):

- `@route("/widgets") @doc("get") op read(): string;` now warns using
its inferred GET verb; a body-bearing operation documented only as
`post` likewise warns.
- `@encodedName("application/json", "wire-name") @doc("wire-name")
sourceName: string;` now warns using its JSON wire name. Documentation
matching only `sourceName` is compliant when JSON serialization renames
it.

These are supported compiler/HTTP semantics, not emitter overrides.
Explicit verbs, normalization, placeholder handling, HTTP parameter-name
precedence, and authored diagnostic targets are preserved.

Each violation targets its semantic declaration. The rule does not
deduplicate distinct semantic instances merely because they share a
source location. It does not project versions, invoke emission, predict
generated schema names, or depend on OpenAPI/emitter/SDK APIs. Valid
authored warnings from older versions remain native findings;
selected-version attribution is separate research evidence.

## Migration evidence and validation

See
[migration.md](https://github.com/Azure/typespec-azure/blob/lintdiff-description-must-not-be-node-name/packages/typespec-lintdiff/test/fixtures/DescriptionMustNotBeNodeName/migration.md)
for the native contract, supported-shape evidence, regenerated full
corpus, verified selected-version attribution reuse, all one-sided
projects, six compilation exclusions, concrete outlier explanations, and
preserved research limitations. The unchanged corpus diagnostic multiset
did not expose the two repaired shapes; focused native tests and emitted
comparison fixtures establish those fixes.

Required cycle1 validation passed: explicit maintained-file Prettier
write/check, package build, changed-TypeScript oxlint with denied
warnings, 41 native predicate tests, 13 strict rule fixtures, the
affected 14-case PATCH fixture group, representative and full corpus
runs, and diff hygiene. Independent persistent local precommit review
was clean on the complete branch diff and verified all supplied
content/receipt hashes, with nine additional native probes.

The documented native contract is covered; arbitrary executable Swagger
equivalence remains partial, not claimed from project overlap or raw
count equality. All 1,005 generated corpus changes were archived and
restored through the exact approved manifest plan. Corpus/coverage
outputs and temporary fixture junctions are excluded from this PR.


## Cycle2 multipart source repair

Confirmed promotion review thread `PRRT_kwDOKoCXvs6rCcjD`
(comment4237005053) exposed a missed authored multipart part name. The
native rule now uses an authored `getHttpPart(program,
type)?.options.name` when present and otherwise the source property
name, including repeated parts via compiler array metadata; JSON encoded
names remain limited to ordinary non-part properties. Path/query/header
precedence and status-code exemption remain intact. Renamed-part
violation, source-name-only compliance, default-name JSON-isolation,
meaningful-documentation, and supported scalar/array/repeated-part
regressions preserve earlier inferred-verb and ordinary JSON-name fixes.
Production uses public compiler/HTTP APIs only.

Validation:47 native tests,15 strict target-rule fixtures and all five
genuinely affected fixture groups pass. The full current468-project
corpus has462 successful projects and six preserved compiler exclusions.
Complete8,499 diagnostic multisets match prior archived results,
allowing conservative selected-version attribution reuse:7,501
findings/142projects. Generated corpus output was archived and
exactly1,005 planned paths restored; none is included in this PR.
Detailed native contract, parity limits and current corpus evidence
remain in the linked migration document above.

Historical Formdata required-gate failure is preserved; explicit user
authorization prospectively excluded its unchanged unmapped data-plane
group without retry or edit. A separately authorized single snapshot
correction only reordered seven identical warnings for preexisting
listener-phase drift; no unrelated semantics changed.

Outer persistent independent local review `f235a949` is clean, with
actual follow-up capability and additional
multiple-operation/shared/spread/repeated-part probes verified.
SourceRepairCycles2/3, development ordinary corrections3/3 and task-wide
reserve2/3 remain unchanged. Fresh GitHub review of this exact repair
head is required before promotion.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@msyyc
Yuchao Yan (msyyc) marked this pull request as ready for review October 12, 2026 04:43
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread packages/typespec-azure-core/src/rules/no-uninformative-doc.ts Outdated
Comment thread packages/typespec-azure-core/test/rules/no-uninformative-doc.test.ts Outdated
Yuchao Yan (msyyc) added a commit that referenced this pull request Oct 19, 2026
## Summary

Update five lint development/promotion skills to prevent the recurring
review feedback in the supplied 58-comment retrospective across 17
migration PRs. Target `feature/lintdiff-migration-new`, the branch
current when this work was requested.

| Review theme | Comments | Prevention |
| --- | ---: | --- |
| Redundant internal change entries | 28 | Inspect and reuse task-owned
unreleased feature/fix coverage before creating entries; preserve
genuinely needed coverage for other packages. |
| Multiple behavior suites for one public rule | 14 | Extend the
canonical suite, found by its imported rule object even when its
historical filename differs from the public name. |
| Repetitive test headings | 13 | Use file-scope cases or meaningful
scenario groups, preserving scoped setup rather than repeating the
rule/filename. |
| Private fixture APIs | 2 | Use supported public imports/decorators;
redesign or remove artificial private-only cases without changing
production scope. |
| Bespoke Markdown parser | 1 | Enforce the existing prohibition without
relocating the parser or losing distinct semantic/example evidence. |

These are five recurring lessons, not 58 independent design judgments:
55 comments explicitly disclose Copilot generation, and three have no
automation disclosure. Original report IDs 37-39 on #5591 and #5654
remain outside the selection.

## Changes

- `typespec-lint-validate`: define canonical suite ownership and
meaningful grouping; clarify genuine public-entry/package tests versus
duplicate rule execution under import guards; require public fixture
APIs.
- `typespec-lint-implement`: centralize unreleased change-entry
reconciliation and include the shared test policies in
implementation/final review.
- `lintdiff-rule-promote`: replace unconditional creation of a test
file/change entry with discovery and reuse; reconcile
acceptance-evidence and review instructions with the shared policies.
- `develop-lintdiff-rule`: reference the shared policies during test
planning and independent review; preserve migration/corpus requirements.
- `create-linter-rule`: apply the same guidance to scaffold cleanup,
existing-rule extensions, public fixtures, and changelog coverage.

## Evidence and boundaries

- [Changelog guidance, report
22](#5502 (comment))
- [Private APIs, report
23](#5502 (comment))
- [One behavior suite per rule, report
36](#5556 (comment))
- [Historical canonical filename, report
48](#5663 (comment))
- [Isolation-suite duplication, report
53](#5665 (comment))
- [Meaningful scenario grouping, report
55](#5673 (comment))
- [Markdown parser removal, report
33](#5551 (comment))

Keep independent utility tests, genuine package/registration evidence,
rule-owned diagnostic regressions, and actual published-example
validation. Keep separate rulesets-package internal coverage when
needed; do not delete all internal entries. Existing production
semantics, audience/enablement, source immutability, parity evidence,
and required validation remain unchanged.

Skills only: no generator, rule implementation/test, package,
dependency, release entry, or CI changes. The scaffolder's redundant
wrapper is explicitly handled by cleanup guidance; changing the
generator is a separate follow-up.

## Validation

- Scoped Prettier write/check on the five changed Markdown files, using
the repository's scalar formatting settings without optional plugins
because the configured TypeSpec plugin has no built output. No
dependencies or submodules were initialized for this documentation
update.
- Relative Markdown file/heading reference checks and full five-file
diff review.
- `git diff --check` and explicit staged-file scope verification.

No package builds, corpus runs, docs regeneration, or repository-wide
formatting/source linting are needed for this Markdown-only change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread packages/typespec-azure-core/test/rules/require-docs.test.ts Outdated
Comment thread packages/typespec-azure-core/test/rules/require-docs.test.ts Outdated
Comment thread packages/typespec-azure-core/test/rules/require-docs.test.ts Outdated
Comment thread packages/typespec-azure-core/test/rules/require-docs.test.ts Outdated
Comment thread packages/typespec-azure-core/src/rules/require-docs.ts Outdated
Run explicit documentation checks from native callbacks, retain missing-doc exemptions, and exercise the public rule without diagnostic filtering. Prune redundant fixtures while preserving multipart boundaries and precise targets.

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

Copy link
Copy Markdown
Member Author

Copilot resolve the merge conflicts in this pull request

…ription-must-not-be-node-name

# Conflicts:
#	packages/typespec-azure-rulesets/test/validate-rules-defined.test.ts

Co-authored-by: msyyc <70930885+msyyc@users.noreply.github.com>

Copilot AI commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Copilot resolve the merge conflicts in this pull request

Resolved in 3612bc1 by merging the latest main, preserving both the documentation-rule tests and main’s ARM opt-in tests. Build, formatting, lint, and all 89 focused tests passed; read-only review found no issues. CodeQL timed out after Actions/Go completed with no alerts, so security analysis is incomplete.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread packages/typespec-azure-core/src/rules/documentation-required.md Outdated
Comment thread packages/typespec-azure-core/src/rules/documentation-required.md Outdated
Comment thread packages/typespec-azure-core/src/rules/documentation.ts Outdated
Comment thread .chronus/changes/no-uninformative-doc-2026-10-10.md Outdated
Comment thread packages/typespec-azure-core/test/rules/require-docs.test.ts Outdated
Comment thread packages/typespec-azure-core/src/rules/require-docs.ts Outdated
Comment thread packages/typespec-azure-core/src/rules/documentation-names.ts Outdated
Timothee Guerin (timotheeguerin) pushed a commit to timotheeguerin/typespec-azure that referenced this pull request Oct 21, 2026
… use-standard-response-codes (Azure#5556)

## Documentation example cleanup (2026-10-21)

Addressed review **5556-R01** in
Azure@a35e14e:
shortened both published examples to the `ArmResourceRead<Widget, Error
= NotFoundResponse>` mistake and standard `ArmResourceRead<Widget>` fix,
assuming `Widget` is defined. No full specification or shared setup
section is published. Rule behavior, enablement, canonical semantic
fixtures and the two existing package changelogs are unchanged.

The earlier standalone compilation receipt below applies to the old full
examples, not these intentionally contextual excerpts. The actual
current Markdown snippets (SHA-256
`4ea418badf18d7e5d04ddb45f1a12e51c32ef8ba2efd3060a86772558a7ad372`) were
compiled once with an explicit public ARM service/Widget context using
`mise exec -- node --input-type=module` and the compiler
`compile`/`NodeHost` API: exactly one expected rule warning for the
incorrect excerpt and zero diagnostics for the correct excerpt. This is
a one-time contextual validation receipt, not standalone or continuous
Markdown coverage; no parser or testing system was added to the
repository.

Fresh local validation: all **40 canonical rule tests** passed; ARM
documentation regeneration completed with existing unrelated
missing-documentation warnings; repository `pnpm format` and `pnpm
lint`, explicit source/generated Markdown formatting checks, and diff
hygiene passed. Unrelated formatter output was excluded. Final-head CI
is tracked separately and is not claimed passed here.

## Review fixes and current-main integration (2026-10-20)

Published in
Azure@c8ae20e.
Merged Azure main `2cd8ba15594de155ae4c79719d7e796577ccdcd7` normally
and retained both
the migration rule and main's new ARM rule registrations in the conflict
resolutions.
Trimmed duplicate POST 201, providerless POST 404, GET 200,
header-bearing 202 and
literal/range fixtures in the canonical suite. One standalone native ARM
positive/negative pair remains, along with singleton-200, broad-range,
service-boundary and diagnostic-cardinality regressions. Rule behavior
and enablement
are unchanged. This supersedes earlier fixture-title mappings where
cases were consolidated.

Fresh local validation on the integrated tree: ARM dependency-closure
build and
production typecheck; **69 tests across four response/helper/merged-rule
suites**;
**7 ruleset tests**; ARM documentation regeneration; root `pnpm format`
and
`pnpm lint`; Chronus status and diff checks. The actual published
examples were
compiled once as unwrapped imported files: one expected warning at the
incorrect
read operation versus zero diagnostics for the correct example.
This receipt is not continuous Markdown coverage. Documentation
regeneration
retains existing unrelated missing-documentation warnings.
Fresh final-head CI is tracked separately; local results do not claim CI
approval.

## Summary

Consolidate **NoErrorCodeResponses** and **GetResponseCodes** into
**`@azure-tools/typespec-azure-resource-manager/use-standard-response-codes`**.
This PR absorbs Azure#5585, including its GET implementation and regression
coverage, instead of introducing a second public
`use-standard-get-response-codes` rule.

Implemented in merge commit
[`a17c998ab9a4e271e9bc812b083ed29db6d062a2`](Azure@a17c998),
preserving both promotion histories. This follows the combined-migration
presentation used in Azure#5294, Azure#5423, and Azure#5663/Azure#5674, and addresses the
[consolidation request on
Azure#5585](Azure#5585 (comment)).

Further review of both response-code checks should continue here.
Closing Azure#5585 as superseded does not imply CI or review approval; its
branch and review history are retained, and existing review threads are
not resolved by this consolidation.

## Combined behavior and legacy-rule mapping

| Swagger validator | Native coverage |
| --- | --- |
|
[NoErrorCodeResponses](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/functions/no-error-code-responses.ts)
| Concrete HTTP operations may only use `200`, `201`, `202`, `204`, or
default. This general policy still checks operations without service or
provider metadata, including operations outside declared services. |
|
[GetResponseCodes](https://github.com/Azure/azure-openapi-validator/blob/1198225afecbb818c3050d4d2a91da92e14e56ce/packages/rulesets/src/spectral/functions/get-response-codes.ts)
| GET operations inside a service namespace or its descendants must
include `200` and use only `200`, `202`, or default. Missing/empty
responses and disallowed statuses produce one warning per invalid GET
operation. |

The rules are related, not interchangeable: GET `202 + default`, `200 +
201`, and `200 + 204` pass the general allowlist but fail the GET
contract. Both contracts are now implemented by one rule and one
operation listener.

- **Scope is preserved, not silently unified.** The general policy
remains service-independent; the stricter GET policy retains Azure#5585's
service ancestry boundary. A GET returning `204` outside services
remains valid under the general policy, while an explicit `404` outside
services is still diagnosed. Provider namespace metadata is not
required.
- **Diagnostics are deliberately deduplicated.** An invalid service GET
receives one GET-specific warning, even when `200` is missing and
several statuses are disallowed. It does not additionally receive the
general policy's warnings. Other operations retain one warning per
disallowed response status, with their existing wording and authored
operation targets.
- Numeric statuses and singleton ranges are equivalent; broader ranges
remain disallowed. Concrete aliases remain independent endpoints, and
existing template guards are retained.
- A GET with only `200` is valid. Default errors and `Location` headers
are not required by either migrated validator function; their separate
rules retain ownership. Response payload/schema correctness is also
outside this rule.
- The central resource-manager ruleset retains a single **disabled
(`false`)** registration for `use-standard-response-codes`. There is no
new data-plane registration or automatic enablement. Explicitly enabling
the combined rule enables both policies in their documented scopes.
- The standalone GET export, source/docs rule files, registration,
generated index entries, ARM matrix row, and duplicate changelog entries
are removed. The absorbed tests are retained as
`use-standard-response-codes-get.test.ts`; one ARM feature changelog and
the existing ruleset internal entry describe the combined migration.

The native rule does not reproduce Swagger emission multiplicity,
SDK-scoped emitter filtering, the general validator's omission of
`x-ms-paths`, or historical API-version projections. The temporary
lintdiff GET rule uses provider ancestry in its mixed ARM/data-plane
runner; the official GET policy retains service ancestry. Exact emitted
diagnostic parity is not claimed.

## Consolidation and provenance

| Check | Immutable reviewed lintdiff source | Promotion history
incorporated here |
| --- | --- | --- |
| NoErrorCodeResponses | Azure#5555 at
[`e4f6aadb`](Azure@e4f6aad)
| Azure#5556 at
[`d6aea03d3`](Azure@d6aea03).
|
| GetResponseCodes | Azure#5584 at
[`99231260`](Azure@9923126)
| Azure#5585 at
[`264dc6a0a`](Azure@264dc6a).
|

The immutable lintdiff source implementations and their existing
migration evidence are unchanged. This is an explicitly requested
consolidation of the official destination rules, not an unreviewed
repair of either temporary source. The existing
`C:\dev\worktrees\promote-lintdiff-no-error-code-responses` worktree was
reused.

## Fixture-to-native test mapping after consolidation

The original NoErrorCodeResponses fixtures retain their native coverage
in `use-standard-response-codes.test.ts`. General-policy literal/range
and per-status diagnostics now use POST so they do not accidentally
exercise the stricter GET branch; the standard ARM read and
documentation-example expectations use the combined rule's GET
diagnostic.

The GetResponseCodes fixtures retain their native coverage in
`use-standard-response-codes-get.test.ts`:

| Original GET fixture | Native test |
| --- | --- |
| get-200-and-default | `accepts the standard ARM resource read
template` |
| get-200-only | `accepts an ARM GET with only a 200 response` |
| get-202-with-location | `accepts an additional 202 response with a
Location header` |
| get-missing-200 | `warns when an ARM GET only returns an error
response` |
| get-extra-201 | `warns once when an ARM GET adds a 201 response` |
| get-extra-response-code | `warns once when an ARM GET adds a 204
response` |
| get-nested-missing-200 | `warns for a GET in a nested ARM namespace` |

Additional combined regressions cover an unfiltered program exercising
both policies without duplicate diagnostics, missing `200` together with
multiple disallowed statuses, GET-only `202 + default`, optional
`Location`, the outside-service general-policy boundary, and the removal
of the standalone GET registration. Existing ARM template/customization
and singleton/broad-range coverage is retained.

## Validation for this consolidation

- Combined native rule and shared-response-helper suites: **56 passed
across 3 files**.
- ARM package build, including TypeSpec library lint: passed.
- ARM documentation regeneration: passed, with existing unrelated
missing-documentation warnings. Generated README, linter reference, and
combined rule page were inspected.
- Azure rulesets build, lint, and tests: passed (**6 tests**), including
one disabled combined rule and no standalone GET registration.
- Required repository `pnpm format` followed by `pnpm lint`: passed. Six
unrelated Astro-only formatting changes were removed from the final
diff.
- Explicit formatting checks for the rule Markdown and ignored generated
rule page, Chronus status, and diff hygiene: passed. The
Chronus-generated duplicate was consolidated into the existing feature
entry.
- The first focused run exposed duplicate GET routes in a new
outside-service test fixture; distinct routes fixed the fixture, and the
complete focused rerun passed.

These are local results, not a claim that fresh GitHub CI or review has
completed. The full ARM suite, full monorepo build, website build, and
corpus were not rerun for this consolidation. Historical results below
do not represent new runs.

<details>
<summary>Historical Azure#5556 promotion notes before consolidation
(superseded where noted above)</summary>


## Test-responsibility cleanup

Applied the guidance merged in Azure#5572 from the [Azure#5507
review](Azure#5507 (comment)).
Removed the manual suppression pipeline, unused-template case, and
namespace-only permutations. Simplified body variants while retaining
exact per-status counts and concrete endpoint targets. Kept the concrete
inherited-interface regression against the rule's previously overbroad
template guard; this is not an ordinary inheritance-only test. No
production code changed.

Current cleanup validation: `mise exec -- pnpm --filter
@azure-tools/typespec-azure-resource-manager exec vitest run
test\rules\use-standard-response-codes.test.ts` passed **29 tests**.
Repository `pnpm format`, `pnpm lint`, and `git diff --check` passed.
Earlier validation counts below describe historical revisions, not this
cleanup; the full test suite was not rerun.

## Summary

Promote `NoErrorCodeResponses` from the local `no-error-code-responses`
rule to

`@azure-tools/typespec-azure-resource-manager/use-standard-response-codes`.
The rule is available but **disabled by default** in the central
resource manager
ruleset. No immediate enablement was requested.

## Original Swagger linter

- linter code:
[NoErrorCodeResponses](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/functions/no-error-code-responses.ts)
- linter doc:
[openapi-authoring-automated-guidelines.md](https://github.com/Azure/azure-rest-api-specs/blob/main/documentation/openapi-authoring-automated-guidelines.md)

The original ARM rule:

- Selects response keys using `$.paths.*.*.responses.*~`.
- Defensively ignores empty or non-string input.
- Allows exactly `200`, `201`, `202`, `204`, and `default`.
- Reports every other response key, including redirects, other success
codes,
explicit error codes, and grouped status keys, at that key's JSON path.

## How the Swagger linter works

The Spectral rule runs with `resolved: false` and compares each selected
response
key against its allowlist; response payload schemas do not affect the
decision.
Its selector omits `x-ms-paths`. AutoRest can also remove SDK-scoped
endpoints
before Swagger validation. Neither emitter selection nor the
`x-ms-paths`
omission is reproduced in this native rule.

## Source TypeSpec lintdiff rule

- Validator: `NoErrorCodeResponses`; canonical slug:
`no-error-code-responses`.
- Local rule: `no-error-code-responses`.
- Source: [original lintdiff
implementation](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-no-error-code-responses/packages/typespec-lintdiff/src/rules/no-error-code-responses.ts).
- Verified canonical repository/branch: `Azure/typespec-azure`,
  `feature/lintdiff-no-error-code-responses`, development PR Azure#5555.
- Pinned reviewed/pushed commit:
`e4f6aadbfd16ebc702a3fd2048bb0ae7a2edbb46`.
- Source worktree: `C:\dev\worktrees\lintdiff-no-error-code-responses`,
clean at promotion.

The named source rule is assumed done for this promotion. It was not
modified.
Development GitHub review completed clean after two rounds at the pinned
SHA.
The reviewed wording identifies a **disallowed response status**, rather
than
incorrectly calling every rejected success/redirect status an error.

## Destination analysis

The agent selected ARM under the default recommendation policy. The
validator
catalog and fixtures are ARM-only, and the exact allowed-status policy
applies
across ARM HTTP methods. It is not generated-SDK naming policy, so TCGC
is not
the owner.

Core is a plausible shared-response-policy alternative, but its existing
`no-error-status-codes` checks only numeric 4xx/5xx responses in
`Azure.*`
namespaces. Extending that data-plane rule to this stricter ARM
allowlist would
change another audience's contract. Existing ARM verb-specific response
rules
also enforce different constraints; none supplies this all-method
allowlist.

The native name `use-standard-response-codes` describes the preferred
ARM set,
including statuses outside 4xx/5xx. Imports are compiler/HTTP and a
local ARM rule
helper only; no reverse ARM-to-TCGC dependency or new package dependency
is introduced.

## How the promoted TypeSpec linter works

An `operation` listener calls `getHttpOperation` to inspect resolved
response status
metadata. The implementation preserves the reviewed allowlist,
singleton/ranged
status handling, warning severity, exact diagnostic wording, and one
warning
per concrete operation and disallowed response status.

Following review, this replaces the initial `getAllHttpServices`
traversal.
Direct enablement checks operations without `@service`, in nested
namespaces,
and outside declared services. This service-independent scope is
intentional and
covered by regression tests; no provider namespace decorator is required
either.
Like ARM's `use-model-request-body`, direct enablement supplies the
intended audience.
Library diagnostic filtering remains the compiler linter context's
responsibility;
the redundant rule-level imported-library filtering test has been
removed.

Concrete aliases retain independent diagnostics and authored locations.
Shared
payload variants do not duplicate an HTTP response, but distinct
offending
statuses remain separate findings. `isTemplateDeclarationOrInstance` and
the
existing `isTemplatedInterfaceOperation` helper exclude generic
operation sources
and templated-interface declarations while retaining concrete inherited
interface
operations. The concrete-interface guard regression is retained because
an
earlier rule-owned `isTemplateInstance` guard incorrectly skipped it;
generic
suppression behavior is no longer re-tested through a manual compiler
pipeline.

No OpenAPI extensions, emitter/SDK metadata, reference-string inference,
or
unsafe compiler mutation participates in the decision. The rule does not
construct historical API-version projections.

## Fixture-to-native test mapping

The fixtures are source evidence; their snapshots are not copied.

| Original lintdiff fixture | Native vitest case | Coverage note |
| --- | --- | --- |
|
[explicit-error-codes](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-no-error-code-responses/packages/typespec-lintdiff/test/fixtures/NoErrorCodeResponses/explicit-error-codes/main.tsp)
| `it("rejects an explicit error response on a standard ARM action")` |
Standard `ArmResourceActionSync` with named `Error = NotFoundResponse`;
exactly one 404 finding. |
|
[default-error-response](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-no-error-code-responses/packages/typespec-lintdiff/test/fixtures/NoErrorCodeResponses/default-error-response/main.tsp)
| `it("accepts a standard ARM action with the default error response")`
| Standard action with omitted default error customization. |
|
[nested-provider-namespace](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-no-error-code-responses/packages/typespec-lintdiff/test/fixtures/NoErrorCodeResponses/nested-provider-namespace/main.tsp)
| `it("rejects a redirect response in a nested provider namespace")` |
Nested concrete action with 302 response. |
|
[status-code-range](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-no-error-code-responses/packages/typespec-lintdiff/test/fixtures/NoErrorCodeResponses/status-code-range/main.tsp)
| `it("rejects a status range on a standard ARM action")` | Concrete
action with 300–399 response range. |
| N/A (source review regression) | `it("reports concrete endpoints, not
the shared template instance")` | Exact diagnostic count and authored
targets for two aliases, without namespace-traversal scaffolding. |
| N/A (framework-only coverage removed) | Not ported (framework-only) |
Suppression belongs to the compiler/linter framework. |
| N/A (source native matrix) | `it("reports each disallowed response
code once across body variants")` | Shared 404 payload variants and
independent 500 response, without inheritance/spread scaffolding. |
| N/A (source native matrix) | `it("checks concrete interface endpoints
despite template exclusion guards")` | Retains the supported-input
regression against an overbroad rule-owned template guard. |
| N/A (framework-only coverage removed) | Not ported (framework-only) |
Uninstantiated-template traversal belongs to the framework. |
| N/A (promotion adaptation) | `it("checks ordinary namespaces without
provider metadata")` | Direct enablement without redundant provider
guard. |
| N/A (framework-only coverage removed) | Not ported (framework-only) |
Namespace traversal adds no distinct rule-owned predicate. |
| N/A (review adaptation) | `it("checks operations without service
metadata")` | Minimal operation without `@service`; no redundant
namespace permutations. |
| N/A (review adaptation) | `it("checks operations outside a declared
service")` | An operation outside a declared service is checked
independently. |
| N/A (documentation validation) | `it("diagnoses the incorrect
documentation example")` | Verbatim standard `ArmResourceRead` incorrect
example compiles and warns. |
| N/A (documentation validation) | `it("accepts the correct
documentation example")` | Verbatim compliant example compiles without
this warning. |

The remaining native cases cover the literal allowlist, rejected
literals,
multiple range families, singleton ranges, standard default errors, and
`ArmResourceRead` response customization.

## Migration evidence

See the source [migration
evidence](https://github.com/Azure/typespec-azure/blob/e4f6aadbfd16ebc702a3fd2048bb0ae7a2edbb46/packages/typespec-lintdiff/test/fixtures/NoErrorCodeResponses/migration.md)
for source fixtures, real-service overlap, count-gap explanations, six
compile
exclusions, and projection limitations. Development review's wording fix
reran
all required checks and the full corpus with unchanged semantic counts;
it did
not rewrite the earlier run's explicitly timestamped evidence. The
review follow-up
here does not claim a new full-corpus run.

## Validation

Review follow-up (`cbde67a32`):

- Focused native suite: **34 passed**, including concrete aliases,
inherited interfaces,
suppression targets, service-independent operations, and both compiled
documentation examples.
Command: `pnpm --filter @azure-tools/typespec-azure-resource-manager
test test/rules/use-standard-response-codes.test.ts --hookTimeout 60000
--maxWorkers 1`.
- ARM package build and TypeSpec library lint: passed.
- Required repository `pnpm format` followed by `pnpm lint`: passed.
- ARM documentation regeneration: passed with existing unrelated
missing-documentation warnings.
- `pnpm change status` and `git diff --check`: passed.
- The full ARM and rulesets suites below are historical promotion
results, not reruns of this follow-up.

Initial promotion validation:

- Missing ARM/compiler/formatter outputs built once using the prepared
dependency
  installation; no dependency changes or reinstall.
- Focused native suite: **31 passed**, including both compiled docs
examples.
- ARM package build and package lint: passed.
- ARM docs regeneration: passed; generated README, linter index, rule
page,
  and manually maintained ARM matrix inspected.
- Explicit formatting/checks: passed, using `--ignore-path NUL` for the
generated
  Markdown scope. Ignored generated rule pages are not force-added.
- Rulesets build, package lint, and tests: passed (**6 tests**),
including explicit
  disabled ARM registration and no data-plane registration.
- Full ARM package suite: **505 passed across 67 files** with checked-in
test
  settings and no timeout/concurrency overrides.
- Chronus status: passed; separate ARM `feature` and rulesets `internal`
entries.

## Validation limitations and recovered attempts

For the review follow-up, three new service-scope regressions failed
against the
old traversal as expected. The first operation-listener implementation
used
`isTemplateInstance`, which also excluded a concrete inherited interface
operation.
The existing regression caught this; using
`isTemplateDeclarationOrInstance`, as
HTTP operation enumeration does, restored that endpoint. All 34 focused
cases then passed.
The 60-second hook timeout and single worker were used for local library
setup;
no checked-in timeout or concurrency settings were changed.

During initial promotion, formatting could not load the unbuilt
workspace Prettier
plugin; building the missing outputs resolved it. The first focused run
passed 27
cases and exposed four test-scaffolding errors (missing service metadata
and injected
import/using conflicts). Only the promotion tests were corrected; all 31
then
passed independently and in the full package run. The initial Chronus
add
commands were successful no-ops on the uncommitted branch; explicit LF
change
entries were added without staging, then validated by Chronus.

Docs regeneration reports documentation-missing warnings for existing
library
diagnostics and unrelated rules, not the new rule. Repository-wide
`validate:pr`
and the website build were not run; the dedicated CI Website job remains
authoritative
for Astro validation.

## Promotion sync policy

The pinned lintdiff source remains immutable during promotion. A
confirmed
source-semantic defect blocks this PR and returns evidence to the owning
queue
for its bounded, authorized return-to-development workflow. Refresh
promotion
only after the repaired source is pushed and reviewed clean; never
repair source
semantics solely in this official copy. The operation-listener change
above is an
explicitly requested destination review adaptation; the pinned source
was not changed.


</details>

## Review follow-up (2026-10-16)

Exported a shared `CompilerTester` with `libraries: []`, without ARM
imports/usings, and retained typed First/Second extraction and response
ambiguity controls. Completed the file-body fixture's required HTTP
metadata fields without changing its model identity. Current
helper/general/absorbed-GET suites: **56 passed**. Scoped helper-source
typecheck and repository format/lint passed. The full test-project
typecheck failed in other existing tests/configuration; that broader
command is not reported as passing.

## Current-main compatibility (2026-10-16, 3df7c4a)

Merged main `88d691bb5` normally in
[`3df7c4aaa`](Azure@3df7c4a).
The ruleset-test resolution retains both the response-status
opt-in/no-standalone-GET assertions and main's redundant-summary
assertion; rule IDs and enablement are unchanged.

After merging: dependency-closure build, **56 focused ARM tests and 7
ruleset tests**, repository format/lint and uncached formatting checks
passed. Scoped production/helper/tester typecheck passed. Full ARM
test-project tsc still fails on pre-existing test assertions/type-only
imports and Vitest configuration; that broader command is not reported
as passing. Fresh required CI checks at this head are pending; the
historical checks above do not establish current-head readiness.

## Review cleanup (October 19, 2026)

Moved GET coverage into `use-standard-response-codes.test.ts` with
scoped setup and deleted the separate GET file. Differing service
boundaries, status/range controls and one-warning GET deduplication
remain. Removed redundant ARM internal entries; combined feature and
separate rulesets coverage remain.

Published in
Azure@1064192.
Fresh focused validation: **51 tests passed**, package production
typecheck, root `pnpm format`, root `pnpm lint`, and diff hygiene
passed. The full test TypeScript project retains pre-existing
diagnostics (38 before, 38 after); the exact-head baseline comparison
found no new diagnostics, accounting explicitly for moved tests and any
removed duplicate fixture. This is not a claim that the full test
TypeScript project is error-free or that pending CI has passed. These
current file-layout/coverage statements supersede earlier descriptions
of the removed test files; historical validation remains historical.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Yuchao Yan (msyyc) and others added 2 commits October 22, 2026 11:51
Use authored property names and native enum-member events; consolidate rule helpers, tests, guidance, and feature release notes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-merge-queue Bot pushed a commit that referenced this pull request Oct 22, 2026
…+ DeleteInOperationName -> use-correct-verb (#5673)

## Summary

Consolidate **PutInOperationName**, **PatchInOperationName**, and
**DeleteInOperationName** into
**`@azure-tools/typespec-client-generator-core/use-correct-verb`**, as
agreed in [the review
discussion](#5673 (comment)).

This PR absorbs the PATCH promotion #5665 and replaces the
already-merged PUT rule from #5457. Both open promotion histories are
preserved by consolidation merge commit
[`d12175650`](d12175650).
Following the combined-migration presentation in #5663, #5556, #5294,
and #5423, further review of these three SDK naming checks belongs here.
Superseding #5665 does not imply CI or review approval; its branch and
review history remain intact.

## Combined behavior and legacy-rule mapping

| Legacy Swagger validator | Previous native rule/promotion | Combined
requirement |
| --- | --- | --- |
|
[PutInOperationName](https://github.com/Azure/azure-openapi-validator/blob/main/docs/put-in-operation-name.md)
| `use-create-for-put`, merged #5457 | PUT common SDK names start with
`create`. |
|
[PatchInOperationName](https://github.com/Azure/azure-openapi-validator/blob/main/docs/patch-in-operation-name.md)
| Proposed `use-update-for-patch`, #5665 | PATCH common SDK names start
with `update`. |
|
[DeleteInOperationName](https://github.com/Azure/azure-openapi-validator/blob/main/docs/delete-in-operation-name.md)
| Proposed `use-delete-for-delete`, this PR | DELETE common SDK names
start with `delete`. |

- A native operation listener resolves HTTP metadata once per eligible
concrete endpoint, using one common SDK-name resolver. Nested services
produce one warning per offending operation. Explicit-service ancestors
and the nonrecursive global fallback are preserved. Prefix matching
remains case-insensitive; GET, POST, and HEAD are not checked.
- `getLibraryName(..., AllScopes)` honors unscoped `@clientName`, exact
names, and the supported friendly-name fallback. Language-specific
overrides and explicit OpenAPI operation IDs do not replace the common
name.
- Diagnostics target original operations. Both ARM and data-plane
service endpoints are supported without requiring provider metadata.
Client-only declarations outside HTTP services are not checked.
- The rule does not mutate namespaces, select emitters, project API
versions, reconstruct historical renamed names, or import AutoRest.
- The single `client-sdk` registration is explicitly **disabled by
default**. Data-plane/resource-manager rulesets and C# defaults are
unchanged.
- Separate rule implementations, their single-consumer traversal helper,
and duplicate per-verb documentation/test files are replaced by one
canonical rule, documentation page, and parameterized behavior suite.
The unnecessary package-level AutoRest import isolation test has been
removed; the canonical rule suite owns behavior coverage.

## Compatibility and migration

**`use-create-for-put` is replaced, not retained as a second public
alias.** Update linter configuration and `#suppress` diagnostic codes to
`use-correct-verb`. Anyone who had explicitly enabled PUT naming
guidance will now opt into PATCH and DELETE checks as well. The proposed
PATCH/DELETE rule names are likewise replaced.

Renaming an already-shipped SDK method can be breaking. The diagnostic
and documentation retain this warning; approved compatibility exceptions
can use operation-level suppression with a justification. This change
does not itself rename generated methods.

The package has one feature Chronus entry describing the consolidated
behavior and configuration migration, plus a separate rulesets
registration entry. Generated linter references, the ARM migration
table, and TCGC documentation knowledge use the combined name.

## Consolidation and immutable source provenance

| Check | Recorded lintdiff source | Native promotion incorporated |
| --- | --- | --- |
| PUT | #5455, `feature/lintdiff-put-in-operation-name`, recorded source
`99cead8b6584f5cc1b0db3bf7810b53aa0eb221b` | Merged #5457;
implementation already present on main. |
| PATCH | #5664, source
[`e009a4f53cc01eaa5c6a9ce85654fb1c4a8a6f4f`](e009a4f)
| #5665 at
[`8710828adc010571458235df8ff50e4019ce3107`](8710828).
|
| DELETE | #5670, source
[`a0b5e8d9a9edee978219c2490c72eac7cc79845b`](a0b5e8d)
| This PR at
[`5fc361c18b79cfdf8460565fc7e3123669cc394d`](5fc361c),
before consolidation. |

The lintdiff sources, fixtures, snapshots, and migration evidence are
not changed. The PUT source SHA is recorded historical provenance; its
GitHub availability is not newly claimed.

The approved native SDK-name adaptation remains intentional: a valid
unscoped SDK override can fix an invalid authored name, or invalidate an
otherwise compliant authored name. Serialized `operationId`
underscore/group-prefix/missing-ID exemptions are not reproduced.
Historical source corpus counts are not fresh combined-rule results, and
exact Swagger diagnostic/count parity is not claimed. The naming policy
remains in TCGC rather than introducing SDK dependencies into Azure Core
or ARM.

## Regression coverage

The canonical suite keeps valid/invalid mappings for all three verbs and
exercises shared casing/prefix boundaries,
common/scoped/exact/friendly-name precedence, explicit OpenAPI IDs,
authored targets, group/underscore contrasts, multiple endpoints, and
service selection once. The redundant naming/verb Cartesian product and
response-status matrix have been removed.

Standard ARM create/patch/delete aliases remain literal fixtures,
including both common-name override directions. A mixed-verb regression
requires three findings together while allowing GET/POST/HEAD. Nested
explicit services require exactly one warning on the original operation;
scope controls cover explicit-service descendants, excluded external
declarations, nonrecursive global operations/direct interfaces, and
concrete aliases versus templates. Public package registration/C#
defaults have a separate registration suite; central ruleset coverage
retains disabled-by-default activation and legacy-ID absence.

The bespoke Markdown reader/fence parser and raw suppression test are
deleted, not relocated. Documentation uses short standard-template
before/after snippets and one focused common-name fix, without a setup
appendix. All four actual final snippets were compiled once in an
explicit public ARM context with the rule enabled: incorrect **3
warnings**, correct/common-name/suppression **0 diagnostics**. This
receipt is one-time evidence, not continuous documentation coverage.
Released-ID migration and SDK compatibility guidance remain intact.

## Validation (selected review fixes, October 21, 2026)

- `mise exec -- pnpm --filter
@azure-tools/typespec-client-generator-core build`: passed, including
production TypeScript and TypeSpec library lint.
- `mise exec -- pnpm --filter
@azure-tools/typespec-client-generator-core test
test/rules/use-correct-verb.test.ts test/linter-registration.test.ts
--maxWorkers=1`: **30 tests passed in 2 files**, unchanged test/hook
timeouts.
- `mise exec -- pnpm --filter @azure-tools/typespec-azure-rulesets test
test/validate-rules-defined.test.ts --maxWorkers=1`: **6 tests passed**.
- TCGC docs regeneration, explicit native/generated Markdown formatting
checks, root `pnpm format` and `pnpm lint`, Chronus status, and diff
hygiene passed.
- Docs regeneration retains existing missing-diagnostic-documentation
and unused-parameter warnings on untouched APIs.
- Initial focused-test collection found the admitted head's new examples
dependency missing. Frozen-lockfile restoration linked JS dependencies
but exited nonzero in unrelated Python preparation (pythonhosted TLS
handshake failure); the dependency closure was then built sequentially.
An initial target annotation error was corrected and the final target
build passed. The install command is not reported as passing.

These are local results for the selected findings, not a claim that
fresh GitHub CI or review is complete. No new full-package/full-monorepo
tests, website build, full test-project typecheck, or lintdiff corpus
comparison is claimed. New human documentation feedback outside the
selected findings remains for separate review; this update does not
claim whole-PR readiness.

<details>
<summary>Original DELETE promotion description before consolidation
(historical)</summary>

## Original Swagger linter

- linter code:
[DeleteInOperationName](https://github.com/Azure/azure-openapi-validator/blob/main/packages/rulesets/src/spectral/functions/delete-in-operation-name.ts)
- linter doc:
[delete-in-operation-name.md](https://github.com/Azure/azure-openapi-validator/blob/main/docs/delete-in-operation-name.md)

Checks:
- [x] Inspect DELETE operations selected from `paths` and `x-ms-paths`.
- [x] Read `operationId`, ignoring absent, empty or non-string values.
- [x] Ignore IDs without an underscore.
- [x] Accept the case-sensitive `Delete` prefix before the underscore or
after a word-character group prefix.
- [x] Report a warning on the offending `operationId` when neither
accepted form matches.

## How the Swagger linter works

The Spectral function checks selected DELETE operation objects and
applies serialized-ID regular expressions. It does not inspect SDK
metadata or require ARM provider metadata. Its underscore/group-prefix
exemptions can accept a Delete-prefixed group with a non-delete method,
or ignore a standalone invalid method ID. Those serialization-dependent
exemptions are intentionally not copied. Native endpoint selection also
avoids warnings on declarations used only for client customization. The
source migration evidence documents emitted-name overrides, historical
version selection, one-sided projects and compilation failures rather
than treating equal totals as proof of equivalence.

## Source TypeSpec lintdiff rule

- Validator ID: `DeleteInOperationName`; canonical slug:
`delete-in-operation-name`.
- Local rule: `tsp-lintdiff-local-linter/delete-in-operation-name`.
- [Original lintdiff source
rule](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/src/rules/delete-in-operation-name.ts).
- Canonical source repository: `Azure/typespec-azure`; source branch:
`feature/lintdiff-delete-in-operation-name`.
- Source draft PR: #5670.
- Immutable source commit: `a0b5e8d9a9edee978219c2490c72eac7cc79845b`;
development GitHub review clean after two Balanced rounds on this final
pushed commit.
- Source worktree: `C:\dev\worktrees\lintdiff-delete-in-operation-name`;
clean, no uncommitted source changes.

The source was assumed done for this promotion run and was not modified.
It checks authored names on concrete HTTP service endpoints, DELETE
only, with a case-insensitive `delete` prefix and warning targets on the
original operation. Initial source commit
`8af7a71258c41b8ca10950023c62cc4633bb24fc` is historical; the reviewed
source above additionally fixes the harness's stale coverage-kind
assertion without changing production behavior.

## Destination analysis

The agent selected `@azure-tools/typespec-client-generator-core` because
the approved naming-family promotion contract governs common SDK method
names. Existing `use-create-for-put` and supported `getLibraryName(...,
AllScopes)` establish that ownership and implementation pattern. The new
public name is `use-delete-for-delete`.

`Both` applicability and compiler/HTTP-only authored-name semantics make
Azure Core a plausible authored-domain alternative. Core's
`use-standard-names` already checks authored DELETE names in data-plane
rulesets, but not the common SDK override domain. An SDK resolver must
not introduce TCGC dependencies into Core or ARM. ARM fixture origin
alone does not establish ARM-only semantics; this rule requires neither
provider metadata nor ARM helpers in production. Existing TCGC
`get-operation-name` is GET-specific and is not equivalent DELETE
coverage.

## How the promoted TypeSpec linter works

The root listener uses `getAllHttpServices` and checks concrete service
operations with verb `delete`. A TCGC context created with `{
mutateNamespace: false }` resolves the common SDK name using
`getLibraryName(context, operation, AllScopes)`. This honors unscoped
client names, exact-name normalization and supported friendly-name
fallback, independently of positive language-specific overrides and
explicit OpenAPI operation IDs. No emitter or API-version projection is
selected, and historical renamed names are not reconstructed.

The prefix remains case-insensitive, severity remains warning and each
finding targets the original operation, including when an override
supplies the displayed SDK name. Group names do not mask an invalid
method name. The authorized adaptation changes only the authored-name
domain to common SDK names; source selection, DELETE condition, prefix
policy and diagnostic targets remain intact. There is no hand-rolled
resolver, serialized-reference inference, namespace mutation or emitter
coupling.

The `client-sdk` ruleset registers the new rule with plain `false`;
ARM/data-plane rulesets and C# default rules are unchanged. Separate
Chronus entries classify destination availability as `feature` and
disabled-only ruleset registration as `internal`.

## Fixture-to-native test mapping

| Original lintdiff fixture | Native vitest case | Coverage note |
| --- | --- | --- |
|
[compliant-with-template](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/compliant-with-template/main.tsp)
| `it("reports a customized standard ARM delete endpoint")` | Actual
source fixture contains a compliant delete and a violating remove
despite its directory name. Replace legacy custom action/suppression
with supported ArmResourceDeleteSync aliases; preserve prefix contrasts.
|
|
[compliant-with-template](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/compliant-with-template/main.tsp)
| `it("accepts a standard ARM delete endpoint")` | Actual source fixture
contains a compliant delete and a violating remove despite its directory
name. Replace legacy custom action/suppression with supported
ArmResourceDeleteSync aliases; preserve prefix contrasts. |
|
[remove-endpoint](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/remove-endpoint/main.tsp)
| `it("reports an invalid HTTP SDK name")` | Concrete remove endpoint
warns; reduced generic HTTP operation preserves the method-name
predicate. |
|
[delete-endpoint](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/delete-endpoint/main.tsp)
| `it("accepts a valid HTTP SDK name")` | Concrete delete-prefixed
endpoint complies. |
|
[common-name-fixes-id](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/common-name-fixes-id/main.tsp)
| `it("accepts a common SDK name override")` | Authorized domain
adaptation: unscoped valid SDK name fixes authored remove; source
authored rule intentionally still warns. |
|
[common-name-invalidates-id](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/common-name-invalidates-id/main.tsp)
| `it("reports an invalid unscoped client name on the authored
operation")` | Authorized domain adaptation: invalid common override
warns despite authored deleteWidget; target remains original
declaration. |
|
[ungrouped-remove](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/ungrouped-remove/main.tsp)
| `it("reports an invalid HTTP SDK name")` | Same minimal standalone
endpoint proves no underscore/group exemption; shared native case is
deliberate. |
|
[delete-group-remove](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/delete-group-remove/main.tsp)
| `it("does not let a Delete-prefixed group mask an invalid method
name")` | Group prefix cannot hide invalid common method name. |
| N/A (documentation regression) | `it("reports the published incorrect
template alias")` | Compile actual Markdown setup and incorrect
ArmResourceDeleteSync alias; require one warning on remove. |
| N/A (documentation regression) | `it("accepts the published correct
template alias")` | Compile actual Markdown correct alias with no
target-rule diagnostics. |
| N/A (documentation regression) | `it("accepts the published template
client name override")` | Compile actual Markdown common-name override
with no target-rule diagnostics. |
| N/A (documentation regression) | `it("accepts the published template
suppression")` | Compile actual Markdown suppression with the rule
explicitly enabled through the compiler linter; require no diagnostics.
|

Additional native cases prove SDK override directions, language-specific
and mixed names, exact names, friendly fallback, explicit-ID
independence, original targets, multiple endpoint findings, non-DELETE
controls, case-insensitive prefixes, source endpoint-selection
regression, and a common client name on a supported standard ARM
deletion alias. Framework-only import exclusion, ordinary
inheritance/traversal, uninstantiated-template and suppression tests
were not mechanically copied. No validator snapshots, fixtures or corpus
payloads are included.

## Migration evidence

See [source
migration.md](https://github.com/Azure/typespec-azure/blob/feature/lintdiff-delete-in-operation-name/packages/typespec-lintdiff/test/fixtures/DeleteInOperationName/migration.md)
for focused tests, representative services, full-corpus counts,
one-sided project explanations, retained compile failures and
uncertainty. Those counts describe the immutable authored-name source,
not fresh SDK-domain equivalence or predicted impact. Promotion did not
rerun the lintdiff harness or corpus.

## Validation

- Required target dependency-closure build, TCGC package build/lint:
exit 0.
- Final emitter-free native rule suite: 28/28, including four tests that
read and compile the actual published Markdown examples; target rule
also passes all 28 cases in the full package run.
- Required TCGC docs regeneration and explicit formatting/check of all
four native/generated Markdown paths with `NUL` ignore override: exit 0;
generated ignored rule page remains unstaged.
- Following template-first skill update #5678 (created before this
documentation update), the incorrect/correct, common-name override, and
suppression examples use `ArmResourceDeleteSync<Widget>` instead of raw
routes. The standalone shared setup includes all imports/usings.
Incorrect `remove` produces exactly the target warning; correct
`delete`, common-name override, and compiler-enabled suppression produce
none. Existing generic HTTP behavior tests remain intact.
- Rulesets build/lint: exit 0; discovery tests: 5/5.
- Separate feature/internal Chronus entries verified LF; plain `pnpm
chronus status`: exit 0. Before commit, both `change add` attempts
reported no changed package, so the documented fallback created only
these two entries.
- Full TCGC initial required run: 1660 passed, one 10000ms per-test
timeout in `arm client with sub clients`, two existing skips; 1663 tests
in 102 files, natural exit 1.
- Single coordinator-granted diagnostic, exactly `mise exec -- pnpm
--filter @azure-tools/typespec-client-generator-core test
--maxWorkers=1`: 1661 passed, zero failures, same two skips and 1663
tests/102 files, natural exit 0. Same code, assertions, dependencies and
10000ms test/hook limits; no pool change. Timeout recovered with
UNPROVEN original cause. The task-wide diagnostic allowance is exhausted
(1/1); the scoped concurrency profile may persist for matching later
package validation without granting another retry.
- Latest full package run after template documentation/test changes:
1665 passed, two unchanged existing skips, 1667 total tests in 102
files, exit 0 using the same `--maxWorkers=1` profile and unchanged
test/hook timeouts. The four added tests account for the population
increase.
- Scoped TypeScript formatting/check and diff hygiene pass. The initial
nine-file promotion patch previously passed read-only cached application
check with an empty index; subsequent review/doc updates are scoped to
the maintained rule documentation and native/rulesets tests.

## Validation limitations

Required docs regeneration exits 0 with existing documentation warnings
for `unnecessary-emitter-option` and unused API `@param` tags on
untouched APIs; these unrelated warnings were retained, not repaired.
The optional repository-wide wrapper was not warranted for this isolated
rule and registration change. No local website/dependency-closure build
was run; CI's Website job remains authoritative. The original full-suite
timeout remains retained evidence, not an environmental diagnosis.

## Promotion sync policy

The source remains immutable during promotion. A verified
source-semantic gap blocks this PR and returns evidence to the owning
queue, which alone may authorize its bounded source-repair cycle.
Refresh native provenance incrementally only after a new clean reviewed
source head; do not repair the source or silently alter its semantics in
the promoted copy. The expressly approved common SDK naming adaptation
is not source repair.

## Review cleanup (October 19, 2026)

Renamed the groups to `HTTP SDK names` and `standard ARM operations`,
preserving their separate SimpleTester and ARM/standalone setup. Removed
the extra DELETE behavior file; focused package-level public-entry
coverage retains the throwing AutoRest guard, now outside the PUT
behavior suite as well. Removed redundant internal entries; feature and
rulesets coverage remain.

Published in
50c4b74.
Fresh focused validation: **68 tests passed**, package production
typecheck, root `pnpm format`, root `pnpm lint`, and diff hygiene
passed. The full test TypeScript project retains pre-existing
diagnostics (15 before, 15 after); the exact-head baseline comparison
found no new diagnostics, accounting explicitly for moved tests and any
removed duplicate fixture. This is not a claim that the full test
TypeScript project is error-free or that pending CI has passed. These
current file-layout/coverage statements supersede earlier descriptions
of the removed test files; historical validation remains historical.

</details>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Mark Cowlishaw <1054056+markcowl@users.noreply.github.com>
Copilot-Session: 8bf3420c-d859-4ac1-81e8-2081d1fded84
Copilot-Session: 832854b7-de67-4f1f-8fe1-6a3e9897aeee
Comment thread packages/typespec-azure-core/src/rules/require-docs.ts Outdated
Keep the single-use messages alongside the rule definition without changing behavior.

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

This branch has not been deployed

No deployments
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-core Issues for @azure-tools/typespec-azure-core library linter Issues related to linter rules meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants