You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/instructions/armapi-review.instructions.md
+7Lines changed: 7 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -505,6 +505,12 @@ The TypeSpec-required rule applies to all new ARM API versions. The full rule de
505
505
506
506
- Properties that are arrays **MUST** have plural names (e.g., `scopes`, `rules`, `addresses`) -- not singular (e.g., `scope`, `rule`, `address`). Singular names suggest a single value, not a collection.
- Arrays of objects in ARM responses **SHOULD** declare which item property uniquely identifies an item via the `x-ms-identifiers` extension. This is what enables ARM tooling (Resource Graph, Change Analysis, What-If) to track individual items across PUT/PATCH/GET responses without treating the array as opaque.
511
+
-**In TypeSpec source, do NOT use `@extension("x-ms-identifiers", ...)`** to control this. `@extension` is forbidden in TypeSpec source for any reason. Use the `@key` decorator on the identity property of the item type, or the `@identifiers(#["<propertyName>"])` decorator on the array property. For arrays whose items have no logical identifier, use `@identifiers(#[])`. See `typespec-review.instructions.md` Section 6.5 (TSP-ARRAY-IDENTIFIERS) for the full rule with examples.
512
+
- A `#suppress` on `missing-x-ms-identifiers` is acceptable **only** as a last resort and must include a real technical justification (no `FIXME`/`TODO`/`TBD`, no "matching another resource" — see `typespec-review.instructions.md` Section 4.1 Warning Suppression Policy).
513
+
508
514
### 8.4 Use Specific Types Instead of Generic Strings (ACTIVELY REVIEW)
509
515
510
516
> **See also:**[`.github/skills/azure-api-review/references/naming-conventions.md`](../skills/azure-api-review/references/naming-conventions.md) for common property names (e.g., `createdAt`, `lastModifiedAt`, `deletedAt`) and resource identifier naming rules (use `Id` suffix, not `Uri` or `Name`).
@@ -1138,6 +1144,7 @@ When reviewing ARM resource-manager swagger files, verify:
Copy file name to clipboardExpand all lines: .github/instructions/typespec-review.instructions.md
+44Lines changed: 44 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -290,6 +290,7 @@ Flag these issues when found:
290
290
-**`@flattenProperty` on new APIs** — do not add new `@flattenProperty` decorators. Flattening creates SDK-breaking issues and is discouraged for new resource types and properties. Existing flattened properties may remain for backward compatibility.
291
291
-**Spread-only model types as full models** — a model type used only for spreading (`...`) into other types **SHOULD** be declared as an `alias` instead. Using `model` for types that are only spread generates unnecessary types in the output. See [TypeSpec alias documentation](https://typespec.io/docs/language-basics/alias) (TypeSpec-BestPractice-01).
292
292
-**Empty model literal `{}` as POST action body** -- when an `ArmResourceActionAsync` or `ArmResourceActionSync` POST action does not need a request body, use `void` instead of `{}`. An empty model literal triggers the `no-empty-model` lint rule, and suppressing it is the wrong fix. Use `void` and remove the suppression.
293
+
-**`@extension(...)` in TypeSpec source** -- never add `@extension(...)` decorators to TypeSpec source for any reason. This includes `@extension("x-ms-identifiers", ...)`, `@extension("x-ms-mutability", ...)`, and any other OpenAPI extension. `@extension` bypasses TypeSpec's type system and emitter conventions. Use the appropriate built-in decorator instead: `@identifiers` / `@key` for `x-ms-identifiers`, `@visibility` for mutability, `@secret` for secret data, etc. (see TSP-ARRAY-IDENTIFIERS for the `x-ms-identifiers` case).
293
294
294
295
---
295
296
@@ -320,6 +321,47 @@ Flag these issues when found:
320
321
- Properties whose names or doc comments clearly indicate numeric values (e.g., `numberOfCores`, `ram`, `vCpu`, `diskSizeGB`) **SHOULD** use `int32`, `int64`, or `float64` — not `string`.
321
322
- If backward compatibility forces a string type for a numeric value, the doc comment **MUST** document the expected format and units.
The `missing-x-ms-identifiers` linter rule fires on array-typed properties whose item models do not declare which property uniquely identifies an item. **Do not silence this rule with `@extension("x-ms-identifiers", [])`.**`@extension` is forbidden in TypeSpec source for any reason (see Section 5 anti-patterns).
327
+
328
+
Use one of the following built-in TypeSpec decorators instead:
329
+
330
+
-**Preferred — `@key` on the identity property of the item type.** The emitter automatically derives `x-ms-identifiers` from `@key`. Use this when the item model has a single, natural identity property:
331
+
332
+
```tsp
333
+
model MoveRequest {
334
+
@key moveId: string;
335
+
from: string;
336
+
to: string;
337
+
}
338
+
339
+
model MoveCollection {
340
+
moves?: MoveRequest[];
341
+
}
342
+
```
343
+
344
+
-**Alternative — `@identifiers(#["<propertyName>", ...])` on the array property.** Use this when the identity property cannot be marked with `@key` on the item type (e.g., the item type is shared and `@key` would conflict, or identity is composed of multiple properties):
345
+
346
+
```tsp
347
+
@identifiers(#["moveId"])
348
+
moves?: MoveRequest[];
349
+
```
350
+
351
+
-**Items genuinely have no identifier — `@identifiers(#[])` on the array property.** For arrays whose items are ordered result records, primitive values, or otherwise have no stable identity field, declare the empty identifier list explicitly. This satisfies the linter without a suppression and documents the design intent:
352
+
353
+
```tsp
354
+
@identifiers(#[])
355
+
testResults?: TestResultRecord[];
356
+
```
357
+
358
+
**Forbidden patterns:**
359
+
360
+
-`@extension("x-ms-identifiers", [])` — never add `@extension` in TypeSpec source for any reason. Replace with `@identifiers(#[])` (or `@key` on the item type).
361
+
-`#suppress "@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers" "..."` — suppression is **only** acceptable as a last resort when neither `@key` nor `@identifiers` is technically feasible (extremely rare). The suppression reason must still meet Section 4.1 rules (real technical justification, no `FIXME`/`TODO`/`TBD`, no "matching another resource"). For brand-new operations and models, suppression is never the right fix — use `@identifiers` or `@key`.
362
+
363
+
When reviewing a new `missing-x-ms-identifiers` suppression, propose `@identifiers` or `@key` as the fix. **Never** suggest `@extension("x-ms-identifiers", ...)`.
364
+
323
365
---
324
366
325
367
## 7. `tspconfig.yaml` Additional Validation
@@ -396,6 +438,8 @@ When reviewing TypeSpec files, verify:
396
438
- ✅ ARM resource ID properties use `armResourceIdentifier` not `string` (TSP-ARM-RESOURCE-ID)
397
439
- ✅ No `@operationId` overrides — restructure interfaces instead
398
440
- ✅ URI properties use `url` scalar type, not plain `string`
441
+
- ✅ Array-typed properties declare item identity via `@key` (on item type) or `@identifiers` (on array property); use `@identifiers(#[])` when items have no identifier (TSP-ARRAY-IDENTIFIERS)
442
+
- ✅ No `@extension(...)` decorators in TypeSpec source — never `@extension("x-ms-identifiers", ...)`, `@extension("x-ms-mutability", ...)`, etc.
399
443
- ✅ Standard ARM base types used (no custom/private resource decorators)
- 'Flagged the @extension("x-ms-identifiers", []) on preflightResults as forbidden -- @extension MUST NOT be used in TypeSpec source for any reason (TSP-ARRAY-IDENTIFIERS)'
153
+
- 'Recommended replacing @extension("x-ms-identifiers", []) with @identifiers(#[]) for preflightResults'
154
+
- 'Flagged the @extension("x-ms-identifiers", ["nodeId"]) on nodes as forbidden -- must use @identifiers(#["nodeId"]) or @key on the item type'
155
+
- 'Flagged the #suppress reason containing "FIXME" on volumes as a placeholder-text violation (TSP-4.1 / Section 4.1 -- Warning Suppression Policy)'
156
+
- 'Flagged the vague "Matching AiGateway pattern" suppression reason on firewallRules -- suppressions must stand on their own with a real technical justification (TSP-4.1)'
157
+
- 'Recommended using @identifiers(#["volumeId"]) on volumes or @key on volumeId in the StorageVolume model instead of suppressing the rule'
158
+
- 'Did NOT flag the @identifiers(#["moveId"]) on pendingMoves -- this is the correct pattern (positive control)'
159
+
- 'Did NOT flag the @identifiers(#[]) on diagnosticSnapshots -- explicit empty identifier list is the correct pattern for arrays with no identity (positive control)'
160
+
- 'Did NOT flag customLabels -- the ClusterLabel item type uses @key on labelKey, which automatically derives x-ms-identifiers (positive control)'
161
+
- 'Never suggested @extension("x-ms-identifiers", ...) as a fix in any finding'
| `segment-casing-violations.tsp` | @segment casing, naming, enum | @segment uses all-lowercase instead of camelCase (TSP-SEGMENT-CASE); PATCH named "patch" not "update" (TSP-PATCH-NAME); @operationId override; enum instead of union; plain string for ARM resource ID. |
102
102
| `secret-and-type-violations.tsp` | Secrets, type constraints | Missing @secret on connectionString/adminPassword/primaryKey (SEC-SECRET-DETECT); #suppress for secret-prop; string instead of utcDateTime; string for numeric diskSizeGB (TSP-NUMERIC-TYPE); plain string for ARM resource ID (TSP-ARM-RESOURCE-ID). |
103
103
| `anti-patterns.tsp` | Common TypeSpec anti-patterns | Empty model `{}` instead of void for POST action; #suppress for no-empty-model; @flattenProperty on new API; default value flowing into PATCH; `\| null` on new property; underscore and ALL_CAPS enum values. |
104
+
| `x-ms-identifiers-violations.tsp` | x-ms-identifiers / @extension | `@extension("x-ms-identifiers", ...)` on array properties (forbidden -- use `@identifiers` or `@key`); `#suppress` of `missing-x-ms-identifiers` with FIXME placeholder text (TSP-4.1); vague "matching another resource" suppression (TSP-ARRAY-IDENTIFIERS). Also contains positive controls: `@identifiers(#["..."])`, `@identifiers(#[])`, and `@key` on item type. |
0 commit comments