Repository navigation
[Swagger Linter Migration] DescriptionMustNotBeNodeName + DescriptiveDescriptionRequired -> documentation-required - #5663
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
All changed packages have been documented.
Show changes
|
📦 Package size report2 packages changed size, +2.81 KB (+0.0%) packed overall.
12 package(s) with no notable change
Packed = gzipped |
commit: |
There was a problem hiding this comment.
🟡 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.
|
You can try these changes here
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
## 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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| const checkNamedTarget = (target: NamedTarget) => { | ||
| const { name } = target; | ||
| if (!name || name.length === 0) { | ||
| return; | ||
| } | ||
|
|
||
| checkTarget(target, name); | ||
| }; |
There was a problem hiding this comment.
Do we need this extra function or can it be combined with the one above?
There was a problem hiding this comment.
The wrapper separates checking named declarations from checking other targets. checkNamedTarget skips unnamed declarations, while checkTarget also handles HTTP verbs, wire names, and unnamed union variants that still need placeholder checks. Keeping them separate makes those different behaviors explicit.
There was a problem hiding this comment.
Combined the wrappers into one checker with a default declaration name. Kept the named-declaration empty-name exemption and the explicit HTTP/JSON/multipart/union-variant name overrides, so this refactor does not broaden documentation policy.
Implemented in 603330abc. Scoped formatting, type-aware lint, package build and the focused native tests passed. Review threads are intentionally left open.
| it("accepts operation documentation matching only its source name", async () => { | ||
| await tester.expect('@get @doc("read") op read(): string;').toBeValid(); | ||
| }); |
There was a problem hiding this comment.
do we want this to be valid? Seems like this should violate the rule too
There was a problem hiding this comment.
This is intentional for compatibility with the legacy Swagger rule. It compares an operation’s description against its HTTP verb (get here), not its TypeSpec operation name or operationId. The test verifies that matching only the source name does not introduce a warning beyond the behavior being migrated.
There was a problem hiding this comment.
Implemented in 5e8dc5927. Documentation that merely repeats either the source operation name or the HTTP verb is now uninformative. These checks were folded into the existing documentation-required rule rather than retained as a separate opt-in rule, with operation-name regressions and the original emitted-name/member coverage transferred. This is an intentional quality-policy expansion, not just wrapper cleanup. It replaces my earlier scope-only response; the thread remains unresolved.
catalinaperalta
left a comment
There was a problem hiding this comment.
Seems pretty complete, just a couple of questions
There was a problem hiding this comment.
I don't think this deserve to be its own rule should just upgrade the documentation-required to make sure that the name is not the node id
There was a problem hiding this comment.
Implemented the requested consolidation in 5e8dc5927: documentation-quality checks now belong to the existing documentation-required rule. The separate no-uninformative-doc registration/docs were removed, while encoded JSON/HTTP names, multipart and enum/union-member semantics and all original regressions were retained. Missing-documentation exemptions remain unchanged. The matching #5674 consolidation was also checked in combination so the two PRs do not create conflicting documentation-rule implementations. These stronger checks are intentional and documented; this replaces my earlier pending-design response without resolving the thread.
Coverage-documentation follow-up: the existing rule documentation now explicitly maps each migrated lintdiff rule to its native check, complementary rules, applicability and intentional semantic differences. This records what consolidation preserves instead of treating registration or overlapping rule names as proof of duplication. Documentation only; behavior is unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Upgrade the existing default-enabled documentation rule instead of introducing no-empty-doc. Preserve missing-doc scopes and exemptions, reject explicit blanks on additional declarations, and transfer the original regression fixtures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve missing-documentation exemptions while rejecting blank required docs and explicit descriptions matching effective names. Compare operation docs against both source names and HTTP verbs, and transfer the regression coverage to the existing default-enabled rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace name-only union variant descriptions with meaningful documentation and regenerate the affected OpenAPI snapshots. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
why do we have a separate file here and a whole dispatcher, this seems uncessarly complex
Merge PR #5674 into #5663, preserving both documentation validators and missing-documentation exemptions. Update combined diagnostic regressions, consolidate rule coverage documentation, and retain one Azure Core fix changelog entry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| ` | ||
| model Widget { | ||
| @doc("") /*name*/name: string; | ||
| @doc(" ") /*value*/value: string; |
There was a problem hiding this comment.
why do all those test have /* */
| return; | ||
| case "Operation": { | ||
| // HTTP validation owns resolution diagnostics; this rule only checks documentation. | ||
| const httpOperation = ignoreDiagnostics(getHttpOperation(context.program, target)); |
There was a problem hiding this comment.
Can we read and normalize the documentation before resolving the HTTP operation? Return early when documentation is absent or normalizes to empty, and check the source-operation-name match first. When it already matches the source name, we can report that without resolving HTTP metadata; only resolve the effective verb when that comparison is still needed. This keeps the same behavior while avoiding unconditional HTTP resolution.

Summary
Consolidate DescriptionMustNotBeNodeName and DescriptiveDescriptionRequired into the existing
@azure-tools/typespec-azure-core/documentation-requiredrule. This PR absorbs #5674, including its implementation and regression coverage, rather than adding separateno-uninformative-docorno-empty-docpublic 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
description, ignoring surrounding whitespace, periods, and case. Operations are checked against both source names and effective HTTP verbs.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
3753a319105eb1be8, including the sample CI fix.72ab22398a3c53e2c.The source lintdiff implementations are unchanged. Both validators share the same authored-documentation traversal and retain the missing-doc exemptions. The combined tests now expect name-only and placeholder descriptions to produce
uninformative, notempty, 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
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
DescriptionMustNotBeNodeNameto@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
description-must-not-be-node-name3753a319f32f3926005536029f9ff32b94f3c905The 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-requiredrule 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
@doctext and doc comments through compilergetDoc; normalizes surrounding whitespace, periods, and case.HttpPartnames, including repeated-part arrays. Unnamed parts use the source property name; JSON encoding does not rename multipart parts.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.
description-matches-namedescriptive-docsliteral-descriptionmodel-description-matches-model-nameoperation-description-matches-http-verboperation-description-matches-typespec-name-onlyparameter-description-matches-emitted-name,parameter-description-matches-source-name-onlyproperty-description-matches-property-namemember-and-key-documentationinferred-http-verbsjson-encoded-property,json-encoded-source-name-onlymultipart-authored-names,multipart-source-name-onlyAdditional 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:
The two existing skips are the unrelated
@exampleand@useRefgroups inno-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 at2c5214be. 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 separateno-empty-docrule/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:
trim()result is empty, at their selected JSON paths.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
DescriptiveDescriptionRequired.descriptive-description-required.descriptive-description-required.Azure/typespec-azure; source draft #5672.lintdiff-descriptive-description-required.72ab22394704fce1a1555c879ff7335da8debf42.C:\dev\worktrees\lintdiff-descriptive-description-required, clean at the pinned source head.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-requiredaddresses 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.membersbecause 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.
it("rejects a whitespace-only property description")it("rejects a whitespace-only parameter description")it("accepts nonblank descriptions on models, properties, and operations")it("targets offending enum members rather than their containing enum")it("targets offending properties rather than their containing model")it("targets offending enum members rather than their containing enum")it("validates the documented incorrect and correct examples")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
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:
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:prand 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.