@ontrails/warden 1.0.0-beta.3 → 1.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/CHANGELOG.md +625 -9
  2. package/README.md +111 -26
  3. package/bin/warden.ts +50 -0
  4. package/package.json +28 -5
  5. package/src/adapter-check.ts +136 -0
  6. package/src/ast.ts +137 -0
  7. package/src/cli.ts +1415 -104
  8. package/src/command.ts +943 -0
  9. package/src/config.ts +184 -0
  10. package/src/draft.ts +22 -0
  11. package/src/drift.ts +122 -22
  12. package/src/fix.ts +120 -0
  13. package/src/formatters.ts +79 -9
  14. package/src/guide.ts +245 -0
  15. package/src/index.ts +215 -14
  16. package/src/project-context.ts +163 -0
  17. package/src/project-rules.ts +290 -0
  18. package/src/resolve.ts +531 -0
  19. package/src/rules/activation-orphan.ts +97 -0
  20. package/src/rules/ast.ts +4008 -86
  21. package/src/rules/circular-refs.ts +154 -0
  22. package/src/rules/cli-command-route-coherence.ts +177 -0
  23. package/src/rules/composes-declarations.ts +837 -0
  24. package/src/rules/context-no-surface-types.ts +78 -15
  25. package/src/rules/contour-exists.ts +251 -0
  26. package/src/rules/contour-ids.ts +15 -0
  27. package/src/rules/dead-internal-trail.ts +161 -0
  28. package/src/rules/dead-public-trail.ts +258 -0
  29. package/src/rules/draft-file-marking.ts +160 -0
  30. package/src/rules/draft-visible-debt.ts +87 -0
  31. package/src/rules/duplicate-public-contract.ts +91 -0
  32. package/src/rules/error-mapping-completeness.ts +290 -0
  33. package/src/rules/example-valid.ts +395 -0
  34. package/src/rules/fires-declarations.ts +735 -0
  35. package/src/rules/implementation-returns-result.ts +1411 -166
  36. package/src/rules/incomplete-accessor-for-standard-op.ts +272 -0
  37. package/src/rules/incomplete-crud.ts +581 -0
  38. package/src/rules/index.ts +234 -18
  39. package/src/rules/intent-propagation.ts +127 -0
  40. package/src/rules/layer-field-name-drift.ts +102 -0
  41. package/src/rules/library-projection-coherence.ts +100 -0
  42. package/src/rules/metadata.ts +755 -0
  43. package/src/rules/missing-reconcile.ts +98 -0
  44. package/src/rules/missing-visibility.ts +110 -0
  45. package/src/rules/no-destructured-compose.ts +194 -0
  46. package/src/rules/no-dev-permit-in-source.ts +99 -0
  47. package/src/rules/no-direct-implementation-call.ts +7 -7
  48. package/src/rules/no-legacy-layer-imports.ts +211 -0
  49. package/src/rules/no-native-error-result.ts +118 -0
  50. package/src/rules/no-redundant-result-error-wrap.ts +384 -0
  51. package/src/rules/no-retired-cross-vocabulary.ts +194 -0
  52. package/src/rules/no-sync-result-assumption.ts +1135 -98
  53. package/src/rules/no-throw-in-detour-recover.ts +225 -0
  54. package/src/rules/no-throw-in-implementation.ts +10 -9
  55. package/src/rules/no-top-level-surface.ts +371 -0
  56. package/src/rules/on-references-exist.ts +194 -0
  57. package/src/rules/orphaned-signal.ts +150 -0
  58. package/src/rules/owner-projection-parity.ts +143 -0
  59. package/src/rules/permit-governance.ts +25 -0
  60. package/src/rules/public-export-example-coverage.ts +562 -0
  61. package/src/rules/public-internal-deep-imports.ts +517 -0
  62. package/src/rules/public-output-schema.ts +29 -0
  63. package/src/rules/public-union-output-discriminants.ts +150 -0
  64. package/src/rules/read-intent-fires.ts +187 -0
  65. package/src/rules/reference-exists.ts +98 -0
  66. package/src/rules/registry-names.ts +155 -0
  67. package/src/rules/resolved-import-boundary.ts +146 -0
  68. package/src/rules/resource-declarations.ts +693 -0
  69. package/src/rules/resource-exists.ts +179 -0
  70. package/src/rules/resource-id-grammar.ts +65 -0
  71. package/src/rules/resource-mock-coverage.ts +115 -0
  72. package/src/rules/scan.ts +38 -25
  73. package/src/rules/scheduled-destroy-intent.ts +44 -0
  74. package/src/rules/signal-graph-coaching.ts +191 -0
  75. package/src/rules/specs.ts +9 -5
  76. package/src/rules/static-resource-accessor-preference.ts +649 -0
  77. package/src/rules/surface-facet-coherence.ts +362 -0
  78. package/src/rules/trail-fork-coaching.ts +616 -0
  79. package/src/rules/trail-versioning-source.ts +1072 -0
  80. package/src/rules/trail-versioning-topo.ts +172 -0
  81. package/src/rules/types.ts +272 -6
  82. package/src/rules/unmaterialized-activation-source.ts +84 -0
  83. package/src/rules/unreachable-detour-shadowing.ts +339 -0
  84. package/src/rules/valid-describe-refs.ts +162 -32
  85. package/src/rules/valid-detour-contract.ts +78 -0
  86. package/src/rules/warden-export-symmetry.ts +540 -0
  87. package/src/rules/warden-rules-use-ast.ts +1114 -0
  88. package/src/rules/webhook-route-collision.ts +243 -0
  89. package/src/trails/activation-orphan.trail.ts +84 -0
  90. package/src/trails/circular-refs.trail.ts +29 -0
  91. package/src/trails/cli-command-route-coherence.trail.ts +47 -0
  92. package/src/trails/composes-declarations.trail.ts +22 -0
  93. package/src/trails/context-no-surface-types.trail.ts +21 -0
  94. package/src/trails/contour-exists.trail.ts +21 -0
  95. package/src/trails/dead-internal-trail.trail.ts +26 -0
  96. package/src/trails/dead-public-trail.trail.ts +31 -0
  97. package/src/trails/deprecation-without-guidance.trail.ts +21 -0
  98. package/src/trails/draft-file-marking.trail.ts +16 -0
  99. package/src/trails/draft-visible-debt.trail.ts +16 -0
  100. package/src/trails/duplicate-public-contract.trail.ts +47 -0
  101. package/src/trails/error-mapping-completeness.trail.ts +30 -0
  102. package/src/trails/example-valid.trail.ts +25 -0
  103. package/src/trails/fires-declarations.trail.ts +23 -0
  104. package/src/trails/fork-without-preserved-blaze.trail.ts +31 -0
  105. package/src/trails/implementation-returns-result.trail.ts +20 -0
  106. package/src/trails/incomplete-accessor-for-standard-op.trail.ts +76 -0
  107. package/src/trails/incomplete-crud.trail.ts +39 -0
  108. package/src/trails/index.ts +83 -0
  109. package/src/trails/intent-propagation.trail.ts +30 -0
  110. package/src/trails/layer-field-name-drift.trail.ts +39 -0
  111. package/src/trails/library-projection-coherence.trail.ts +43 -0
  112. package/src/trails/marker-schema-unsupported.trail.ts +23 -0
  113. package/src/trails/missing-reconcile.trail.ts +33 -0
  114. package/src/trails/missing-visibility.trail.ts +22 -0
  115. package/src/trails/no-destructured-compose.trail.ts +44 -0
  116. package/src/trails/no-dev-permit-in-source.trail.ts +16 -0
  117. package/src/trails/no-direct-implementation-call.trail.ts +16 -0
  118. package/src/trails/no-legacy-layer-imports.trail.ts +41 -0
  119. package/src/trails/no-native-error-result.trail.ts +18 -0
  120. package/src/trails/no-redundant-result-error-wrap.trail.ts +55 -0
  121. package/src/trails/no-retired-cross-vocabulary.trail.ts +42 -0
  122. package/src/trails/no-sync-result-assumption.trail.ts +19 -0
  123. package/src/trails/no-throw-in-detour-recover.trail.ts +24 -0
  124. package/src/trails/no-throw-in-implementation.trail.ts +20 -0
  125. package/src/trails/no-top-level-surface.trail.ts +43 -0
  126. package/src/trails/on-references-exist.trail.ts +21 -0
  127. package/src/trails/orphaned-signal.trail.ts +36 -0
  128. package/src/trails/owner-projection-parity.trail.ts +26 -0
  129. package/src/trails/pending-force.trail.ts +21 -0
  130. package/src/trails/permit-governance.trail.ts +51 -0
  131. package/src/trails/prefer-schema-inference.trail.ts +21 -0
  132. package/src/trails/public-export-example-coverage.trail.ts +16 -0
  133. package/src/trails/public-internal-deep-imports.trail.ts +94 -0
  134. package/src/trails/public-output-schema.trail.ts +55 -0
  135. package/src/trails/public-union-output-discriminants.trail.ts +33 -0
  136. package/src/trails/read-intent-fires.trail.ts +20 -0
  137. package/src/trails/reference-exists.trail.ts +25 -0
  138. package/src/trails/resolved-import-boundary.trail.ts +109 -0
  139. package/src/trails/resource-declarations.trail.ts +25 -0
  140. package/src/trails/resource-exists.trail.ts +27 -0
  141. package/src/trails/resource-id-grammar.trail.ts +39 -0
  142. package/src/trails/resource-mock-coverage.trail.ts +40 -0
  143. package/src/trails/run.ts +162 -0
  144. package/src/trails/scheduled-destroy-intent.trail.ts +56 -0
  145. package/src/trails/schema.ts +198 -0
  146. package/src/trails/signal-graph-coaching.trail.ts +77 -0
  147. package/src/trails/static-resource-accessor-preference.trail.ts +25 -0
  148. package/src/trails/surface-facet-coherence.trail.ts +25 -0
  149. package/src/trails/topo.ts +6 -0
  150. package/src/trails/trail-fork-coaching.trail.ts +42 -0
  151. package/src/trails/unmaterialized-activation-source.trail.ts +72 -0
  152. package/src/trails/unreachable-detour-shadowing.trail.ts +45 -0
  153. package/src/trails/valid-describe-refs.trail.ts +18 -0
  154. package/src/trails/valid-detour-contract.trail.ts +71 -0
  155. package/src/trails/version-gap.trail.ts +35 -0
  156. package/src/trails/version-pinned-compose.trail.ts +23 -0
  157. package/src/trails/version-without-examples.trail.ts +38 -0
  158. package/src/trails/warden-export-symmetry.trail.ts +16 -0
  159. package/src/trails/warden-rules-use-ast.trail.ts +64 -0
  160. package/src/trails/webhook-route-collision.trail.ts +50 -0
  161. package/src/trails/wrap-rule.ts +214 -0
  162. package/src/workspaces.ts +238 -0
  163. package/.turbo/turbo-build.log +0 -1
  164. package/.turbo/turbo-lint.log +0 -3
  165. package/.turbo/turbo-typecheck.log +0 -1
  166. package/dist/cli.d.ts +0 -46
  167. package/dist/cli.d.ts.map +0 -1
  168. package/dist/cli.js +0 -221
  169. package/dist/cli.js.map +0 -1
  170. package/dist/drift.d.ts +0 -26
  171. package/dist/drift.d.ts.map +0 -1
  172. package/dist/drift.js +0 -27
  173. package/dist/drift.js.map +0 -1
  174. package/dist/formatters.d.ts +0 -29
  175. package/dist/formatters.d.ts.map +0 -1
  176. package/dist/formatters.js +0 -87
  177. package/dist/formatters.js.map +0 -1
  178. package/dist/index.d.ts +0 -26
  179. package/dist/index.d.ts.map +0 -1
  180. package/dist/index.js +0 -26
  181. package/dist/index.js.map +0 -1
  182. package/dist/rules/ast.d.ts +0 -41
  183. package/dist/rules/ast.d.ts.map +0 -1
  184. package/dist/rules/ast.js +0 -163
  185. package/dist/rules/ast.js.map +0 -1
  186. package/dist/rules/context-no-surface-types.d.ts +0 -12
  187. package/dist/rules/context-no-surface-types.d.ts.map +0 -1
  188. package/dist/rules/context-no-surface-types.js +0 -96
  189. package/dist/rules/context-no-surface-types.js.map +0 -1
  190. package/dist/rules/implementation-returns-result.d.ts +0 -13
  191. package/dist/rules/implementation-returns-result.d.ts.map +0 -1
  192. package/dist/rules/implementation-returns-result.js +0 -277
  193. package/dist/rules/implementation-returns-result.js.map +0 -1
  194. package/dist/rules/index.d.ts +0 -22
  195. package/dist/rules/index.d.ts.map +0 -1
  196. package/dist/rules/index.js +0 -41
  197. package/dist/rules/index.js.map +0 -1
  198. package/dist/rules/no-direct-impl-in-route.d.ts +0 -12
  199. package/dist/rules/no-direct-impl-in-route.d.ts.map +0 -1
  200. package/dist/rules/no-direct-impl-in-route.js +0 -46
  201. package/dist/rules/no-direct-impl-in-route.js.map +0 -1
  202. package/dist/rules/no-direct-implementation-call.d.ts +0 -12
  203. package/dist/rules/no-direct-implementation-call.d.ts.map +0 -1
  204. package/dist/rules/no-direct-implementation-call.js +0 -39
  205. package/dist/rules/no-direct-implementation-call.js.map +0 -1
  206. package/dist/rules/no-sync-result-assumption.d.ts +0 -6
  207. package/dist/rules/no-sync-result-assumption.d.ts.map +0 -1
  208. package/dist/rules/no-sync-result-assumption.js +0 -98
  209. package/dist/rules/no-sync-result-assumption.js.map +0 -1
  210. package/dist/rules/no-throw-in-detour-target.d.ts +0 -12
  211. package/dist/rules/no-throw-in-detour-target.d.ts.map +0 -1
  212. package/dist/rules/no-throw-in-detour-target.js +0 -87
  213. package/dist/rules/no-throw-in-detour-target.js.map +0 -1
  214. package/dist/rules/no-throw-in-implementation.d.ts +0 -9
  215. package/dist/rules/no-throw-in-implementation.d.ts.map +0 -1
  216. package/dist/rules/no-throw-in-implementation.js +0 -34
  217. package/dist/rules/no-throw-in-implementation.js.map +0 -1
  218. package/dist/rules/prefer-schema-inference.d.ts +0 -7
  219. package/dist/rules/prefer-schema-inference.d.ts.map +0 -1
  220. package/dist/rules/prefer-schema-inference.js +0 -86
  221. package/dist/rules/prefer-schema-inference.js.map +0 -1
  222. package/dist/rules/scan.d.ts +0 -8
  223. package/dist/rules/scan.d.ts.map +0 -1
  224. package/dist/rules/scan.js +0 -32
  225. package/dist/rules/scan.js.map +0 -1
  226. package/dist/rules/specs.d.ts +0 -29
  227. package/dist/rules/specs.d.ts.map +0 -1
  228. package/dist/rules/specs.js +0 -192
  229. package/dist/rules/specs.js.map +0 -1
  230. package/dist/rules/structure.d.ts +0 -13
  231. package/dist/rules/structure.d.ts.map +0 -1
  232. package/dist/rules/structure.js +0 -142
  233. package/dist/rules/structure.js.map +0 -1
  234. package/dist/rules/types.d.ts +0 -52
  235. package/dist/rules/types.d.ts.map +0 -1
  236. package/dist/rules/types.js +0 -2
  237. package/dist/rules/types.js.map +0 -1
  238. package/dist/rules/valid-describe-refs.d.ts +0 -7
  239. package/dist/rules/valid-describe-refs.d.ts.map +0 -1
  240. package/dist/rules/valid-describe-refs.js +0 -51
  241. package/dist/rules/valid-describe-refs.js.map +0 -1
  242. package/dist/rules/valid-detour-refs.d.ts +0 -6
  243. package/dist/rules/valid-detour-refs.d.ts.map +0 -1
  244. package/dist/rules/valid-detour-refs.js +0 -116
  245. package/dist/rules/valid-detour-refs.js.map +0 -1
  246. package/src/__tests__/cli.test.ts +0 -198
  247. package/src/__tests__/drift.test.ts +0 -74
  248. package/src/__tests__/formatters.test.ts +0 -157
  249. package/src/__tests__/implementation-returns-result.test.ts +0 -128
  250. package/src/__tests__/no-direct-implementation-call.test.ts +0 -83
  251. package/src/__tests__/no-sync-result-assumption.test.ts +0 -85
  252. package/src/__tests__/no-throw-in-detour-target.test.ts +0 -78
  253. package/src/__tests__/prefer-schema-inference.test.ts +0 -84
  254. package/src/__tests__/rules.test.ts +0 -215
  255. package/src/__tests__/valid-describe-refs.test.ts +0 -60
  256. package/src/rules/no-direct-impl-in-route.ts +0 -77
  257. package/src/rules/no-throw-in-detour-target.ts +0 -150
  258. package/src/rules/valid-detour-refs.ts +0 -187
  259. package/tsconfig.json +0 -9
  260. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Flags retired `cross` composition vocabulary after the beta.19 compose cutover.
3
+ *
4
+ * Exact authored terms that have a mechanical successor carry safe
5
+ * `term-rewrite` edits. Larger identifiers and type prefixes remain
6
+ * review-required because the text-only rule cannot prove the intended symbol
7
+ * boundary.
8
+ */
9
+ import { resolve, sep } from 'node:path';
10
+
11
+ import type { WardenDiagnostic, WardenFix, WardenRule } from './types.js';
12
+
13
+ const RULE_NAME = 'no-retired-cross-vocabulary';
14
+
15
+ const SAFE_REWRITES = [
16
+ { from: 'ctx.cross', to: 'ctx.compose' },
17
+ { from: 'crossInput', to: 'composeInput' },
18
+ { from: 'crosses', to: 'composes' },
19
+ ] as const;
20
+
21
+ const REVIEW_TERMS = ['Cross', 'cross'] as const;
22
+
23
+ const IDENTIFIER_CHAR = /[$0-9A-Z_a-z]/u;
24
+
25
+ const ALLOWED_PATH_SUFFIXES: readonly string[] = [
26
+ '/docs/migration/cross-to-compose.md',
27
+ '/docs/releases/beta15-to-beta19.md',
28
+ '/docs/adr/0049-composition-is-compose-not-cross.md',
29
+ '/packages/warden/src/rules/no-retired-cross-vocabulary.ts',
30
+ '/packages/warden/src/rules/metadata.ts',
31
+ '/packages/warden/src/trails/no-retired-cross-vocabulary.trail.ts',
32
+ '/scripts/vocab-cutover-rewrite.ts',
33
+ ];
34
+
35
+ interface SafeRewriteMatch {
36
+ readonly from: string;
37
+ readonly index: number;
38
+ readonly to: string;
39
+ }
40
+
41
+ interface ReviewMatch {
42
+ readonly index: number;
43
+ readonly term: (typeof REVIEW_TERMS)[number];
44
+ }
45
+
46
+ const normalizePath = (filePath: string): string =>
47
+ resolve(filePath).split(sep).join('/');
48
+
49
+ const isAllowedFile = (filePath: string): boolean => {
50
+ const normalized = normalizePath(filePath);
51
+ return ALLOWED_PATH_SUFFIXES.some((suffix) => normalized.endsWith(suffix));
52
+ };
53
+
54
+ const isIdentifierChar = (value: string): boolean =>
55
+ value !== '' && IDENTIFIER_CHAR.test(value);
56
+
57
+ const isReviewPrefix = (
58
+ sourceCode: string,
59
+ index: number,
60
+ term: string
61
+ ): boolean => !(term === 'cross' && sourceCode.startsWith('crosses', index));
62
+
63
+ const isStandaloneSpan = (
64
+ sourceCode: string,
65
+ start: number,
66
+ end: number
67
+ ): boolean => {
68
+ const before = start === 0 ? '' : (sourceCode[start - 1] ?? '');
69
+ const after = sourceCode[end] ?? '';
70
+ return !(isIdentifierChar(before) || isIdentifierChar(after));
71
+ };
72
+
73
+ const findSafeRewriteMatches = (
74
+ sourceCode: string
75
+ ): readonly SafeRewriteMatch[] => {
76
+ const matches: SafeRewriteMatch[] = [];
77
+ for (const rewrite of SAFE_REWRITES) {
78
+ let fromIndex = 0;
79
+ while (fromIndex < sourceCode.length) {
80
+ const index = sourceCode.indexOf(rewrite.from, fromIndex);
81
+ if (index === -1) {
82
+ break;
83
+ }
84
+ const end = index + rewrite.from.length;
85
+ if (isStandaloneSpan(sourceCode, index, end)) {
86
+ matches.push({ ...rewrite, index });
87
+ }
88
+ fromIndex = end;
89
+ }
90
+ }
91
+ return matches.toSorted((a, b) => a.index - b.index);
92
+ };
93
+
94
+ const findReviewMatches = (sourceCode: string): readonly ReviewMatch[] => {
95
+ const safeSpans = findSafeRewriteMatches(sourceCode).map((match) => ({
96
+ end: match.index + match.from.length,
97
+ start: match.index,
98
+ }));
99
+ const isInsideSafeSpan = (index: number): boolean =>
100
+ safeSpans.some((span) => index >= span.start && index < span.end);
101
+
102
+ const matches: ReviewMatch[] = [];
103
+ for (const term of REVIEW_TERMS) {
104
+ let fromIndex = 0;
105
+ while (fromIndex < sourceCode.length) {
106
+ const index = sourceCode.indexOf(term, fromIndex);
107
+ if (index === -1) {
108
+ break;
109
+ }
110
+ const end = index + term.length;
111
+ if (!isInsideSafeSpan(index)) {
112
+ const before = index === 0 ? '' : (sourceCode[index - 1] ?? '');
113
+ const after = sourceCode[end] ?? '';
114
+ if (
115
+ !isIdentifierChar(before) &&
116
+ isIdentifierChar(after) &&
117
+ isReviewPrefix(sourceCode, index, term)
118
+ ) {
119
+ matches.push({ index, term });
120
+ }
121
+ }
122
+ fromIndex = end;
123
+ }
124
+ }
125
+ return matches.toSorted((a, b) => a.index - b.index);
126
+ };
127
+
128
+ const lineForOffset = (sourceCode: string, offset: number): number => {
129
+ let line = 1;
130
+ for (let i = 0; i < offset; i += 1) {
131
+ if (sourceCode.codePointAt(i) === 10) {
132
+ line += 1;
133
+ }
134
+ }
135
+ return line;
136
+ };
137
+
138
+ const safeFix = (match: SafeRewriteMatch): WardenFix => ({
139
+ class: 'term-rewrite',
140
+ edits: [
141
+ {
142
+ end: match.index + match.from.length,
143
+ replacement: match.to,
144
+ start: match.index,
145
+ },
146
+ ],
147
+ reason: `Retired composition vocabulary '${match.from}' has a mechanical beta.19 replacement '${match.to}'.`,
148
+ safety: 'safe',
149
+ });
150
+
151
+ const reviewFix = (term: string): WardenFix => ({
152
+ class: 'term-rewrite',
153
+ reason: `Retired composition vocabulary '${term}' appears in a larger or ambiguous form. Review before migrating to compose vocabulary.`,
154
+ safety: 'review',
155
+ });
156
+
157
+ const safeMessage = (match: SafeRewriteMatch): string =>
158
+ `Retired composition vocabulary '${match.from}' should be '${match.to}' after the beta.19 compose cutover.`;
159
+
160
+ const reviewMessage = (term: string): string =>
161
+ `Retired composition vocabulary '${term}' needs review before migrating to compose vocabulary.`;
162
+
163
+ export const noRetiredCrossVocabulary: WardenRule = {
164
+ check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
165
+ if (isAllowedFile(filePath)) {
166
+ return [];
167
+ }
168
+
169
+ const reviewMatches = findReviewMatches(sourceCode);
170
+ if (reviewMatches.length > 0) {
171
+ return reviewMatches.map((match) => ({
172
+ filePath,
173
+ fix: reviewFix(match.term),
174
+ line: lineForOffset(sourceCode, match.index),
175
+ message: reviewMessage(match.term),
176
+ rule: RULE_NAME,
177
+ severity: 'error',
178
+ }));
179
+ }
180
+
181
+ return findSafeRewriteMatches(sourceCode).map((match) => ({
182
+ filePath,
183
+ fix: safeFix(match),
184
+ line: lineForOffset(sourceCode, match.index),
185
+ message: safeMessage(match),
186
+ rule: RULE_NAME,
187
+ severity: 'error',
188
+ }));
189
+ },
190
+ description:
191
+ 'Disallow retired cross composition vocabulary after the beta.19 compose cutover.',
192
+ name: RULE_NAME,
193
+ severity: 'error',
194
+ };