@ontrails/warden 1.0.0-beta.4 → 1.0.0-beta.42

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 (279) hide show
  1. package/CHANGELOG.md +837 -13
  2. package/README.md +133 -26
  3. package/bin/warden.ts +51 -0
  4. package/package.json +27 -6
  5. package/src/adapter-check.ts +136 -0
  6. package/src/cli.ts +1570 -105
  7. package/src/command.ts +986 -0
  8. package/src/config.ts +193 -0
  9. package/src/draft.ts +22 -0
  10. package/src/drift.ts +233 -23
  11. package/src/fix.ts +126 -0
  12. package/src/formatters.ts +78 -13
  13. package/src/guide.ts +245 -0
  14. package/src/index.ts +247 -15
  15. package/src/project-context.ts +446 -0
  16. package/src/project-rules.ts +290 -0
  17. package/src/resolve.ts +531 -0
  18. package/src/rules/activation-orphan.ts +97 -0
  19. package/src/rules/captured-kernel.ts +375 -0
  20. package/src/rules/circular-refs.ts +150 -0
  21. package/src/rules/cli-command-route-coherence.ts +177 -0
  22. package/src/rules/composes-declarations.ts +839 -0
  23. package/src/rules/context-no-surface-types.ts +79 -15
  24. package/src/rules/dead-internal-trail.ts +161 -0
  25. package/src/rules/dead-public-trail.ts +258 -0
  26. package/src/rules/draft-file-marking.ts +155 -0
  27. package/src/rules/draft-visible-debt.ts +82 -0
  28. package/src/rules/duplicate-exported-symbol.ts +211 -0
  29. package/src/rules/duplicate-public-contract.ts +137 -0
  30. package/src/rules/entity-exists.ts +254 -0
  31. package/src/rules/entity-ids.ts +15 -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 +740 -0
  35. package/src/rules/governed-symbol-residue.ts +438 -0
  36. package/src/rules/implementation-returns-result.ts +1409 -166
  37. package/src/rules/incomplete-accessor-for-standard-op.ts +272 -0
  38. package/src/rules/incomplete-crud.ts +583 -0
  39. package/src/rules/index.ts +277 -10
  40. package/src/rules/intent-propagation.ts +125 -0
  41. package/src/rules/layer-field-name-drift.ts +102 -0
  42. package/src/rules/library-projection-coherence.ts +100 -0
  43. package/src/rules/metadata.ts +871 -0
  44. package/src/rules/missing-reconcile.ts +97 -0
  45. package/src/rules/missing-visibility.ts +111 -0
  46. package/src/rules/no-destructured-compose.ts +196 -0
  47. package/src/rules/no-dev-permit-in-source.ts +99 -0
  48. package/src/rules/no-direct-implementation-call.ts +12 -7
  49. package/src/rules/no-legacy-cli-alias-export.ts +247 -0
  50. package/src/rules/no-legacy-layer-imports.ts +211 -0
  51. package/src/rules/no-native-error-result.ts +118 -0
  52. package/src/rules/no-redundant-result-error-wrap.ts +384 -0
  53. package/src/rules/no-retired-cross-vocabulary.ts +204 -0
  54. package/src/rules/no-sync-result-assumption.ts +1141 -98
  55. package/src/rules/no-throw-in-detour-recover.ts +225 -0
  56. package/src/rules/no-throw-in-implementation.ts +15 -8
  57. package/src/rules/no-top-level-surface.ts +371 -0
  58. package/src/rules/on-references-exist.ts +194 -0
  59. package/src/rules/orphaned-signal.ts +149 -0
  60. package/src/rules/owner-projection-parity.ts +143 -0
  61. package/src/rules/permit-governance.ts +25 -0
  62. package/src/rules/public-export-example-coverage.ts +573 -0
  63. package/src/rules/public-internal-deep-imports.ts +456 -0
  64. package/src/rules/public-output-schema.ts +29 -0
  65. package/src/rules/public-union-output-discriminants.ts +150 -0
  66. package/src/rules/read-intent-fires.ts +188 -0
  67. package/src/rules/reference-exists.ts +97 -0
  68. package/src/rules/registry-names.ts +167 -0
  69. package/src/rules/resolved-import-boundary.ts +146 -0
  70. package/src/rules/resource-declarations.ts +697 -0
  71. package/src/rules/resource-exists.ts +181 -0
  72. package/src/rules/resource-id-grammar.ts +65 -0
  73. package/src/rules/resource-mock-coverage.ts +115 -0
  74. package/src/rules/retired-vocabulary.ts +633 -0
  75. package/src/rules/scan.ts +38 -25
  76. package/src/rules/scheduled-destroy-intent.ts +44 -0
  77. package/src/rules/signal-graph-coaching.ts +220 -0
  78. package/src/rules/source/composition.ts +165 -0
  79. package/src/rules/source/drafts.ts +164 -0
  80. package/src/rules/source/entities.ts +618 -0
  81. package/src/rules/source/pragmas.ts +45 -0
  82. package/src/rules/source/resources.ts +64 -0
  83. package/src/rules/source/signals.ts +397 -0
  84. package/src/rules/source/stores.ts +310 -0
  85. package/src/rules/specs.ts +9 -5
  86. package/src/rules/static-resource-accessor-preference.ts +653 -0
  87. package/src/rules/surface-overlay-coherence.ts +262 -0
  88. package/src/rules/surface-trailhead-coherence.ts +366 -0
  89. package/src/rules/trail-fork-coaching.ts +625 -0
  90. package/src/rules/trail-versioning-source.ts +1076 -0
  91. package/src/rules/trail-versioning-topo.ts +172 -0
  92. package/src/rules/trailhead-override-divergence.ts +356 -0
  93. package/src/rules/types.ts +354 -8
  94. package/src/rules/unmaterialized-activation-source.ts +85 -0
  95. package/src/rules/unreachable-detour-shadowing.ts +339 -0
  96. package/src/rules/valid-describe-refs.ts +162 -32
  97. package/src/rules/valid-detour-contract.ts +78 -0
  98. package/src/rules/warden-export-symmetry.ts +540 -0
  99. package/src/rules/warden-rules-use-ast.ts +1109 -0
  100. package/src/rules/webhook-route-collision.ts +306 -0
  101. package/src/trails/activation-orphan.trail.ts +84 -0
  102. package/src/trails/captured-kernel.trail.ts +108 -0
  103. package/src/trails/circular-refs.trail.ts +29 -0
  104. package/src/trails/cli-command-route-coherence.trail.ts +47 -0
  105. package/src/trails/composes-declarations.trail.ts +22 -0
  106. package/src/trails/context-no-surface-types.trail.ts +21 -0
  107. package/src/trails/dead-internal-trail.trail.ts +26 -0
  108. package/src/trails/dead-public-trail.trail.ts +31 -0
  109. package/src/trails/deprecation-without-guidance.trail.ts +21 -0
  110. package/src/trails/draft-file-marking.trail.ts +16 -0
  111. package/src/trails/draft-visible-debt.trail.ts +16 -0
  112. package/src/trails/duplicate-exported-symbol.trail.ts +48 -0
  113. package/src/trails/duplicate-public-contract.trail.ts +47 -0
  114. package/src/trails/entity-exists.trail.ts +21 -0
  115. package/src/trails/error-mapping-completeness.trail.ts +30 -0
  116. package/src/trails/example-valid.trail.ts +25 -0
  117. package/src/trails/fires-declarations.trail.ts +23 -0
  118. package/src/trails/fork-without-preserved-implementation.trail.ts +31 -0
  119. package/src/trails/governed-symbol-residue.trail.ts +24 -0
  120. package/src/trails/implementation-returns-result.trail.ts +20 -0
  121. package/src/trails/incomplete-accessor-for-standard-op.trail.ts +76 -0
  122. package/src/trails/incomplete-crud.trail.ts +39 -0
  123. package/src/trails/index.ts +89 -0
  124. package/src/trails/intent-propagation.trail.ts +30 -0
  125. package/src/trails/layer-field-name-drift.trail.ts +39 -0
  126. package/src/trails/library-projection-coherence.trail.ts +43 -0
  127. package/src/trails/marker-schema-unsupported.trail.ts +23 -0
  128. package/src/trails/missing-reconcile.trail.ts +33 -0
  129. package/src/trails/missing-visibility.trail.ts +22 -0
  130. package/src/trails/no-destructured-compose.trail.ts +44 -0
  131. package/src/trails/no-dev-permit-in-source.trail.ts +16 -0
  132. package/src/trails/no-direct-implementation-call.trail.ts +16 -0
  133. package/src/trails/no-legacy-cli-alias-export.trail.ts +41 -0
  134. package/src/trails/no-legacy-layer-imports.trail.ts +41 -0
  135. package/src/trails/no-native-error-result.trail.ts +18 -0
  136. package/src/trails/no-redundant-result-error-wrap.trail.ts +55 -0
  137. package/src/trails/no-retired-cross-vocabulary.trail.ts +42 -0
  138. package/src/trails/no-sync-result-assumption.trail.ts +19 -0
  139. package/src/trails/no-throw-in-detour-recover.trail.ts +24 -0
  140. package/src/trails/no-throw-in-implementation.trail.ts +20 -0
  141. package/src/trails/no-top-level-surface.trail.ts +43 -0
  142. package/src/trails/on-references-exist.trail.ts +21 -0
  143. package/src/trails/orphaned-signal.trail.ts +36 -0
  144. package/src/trails/owner-projection-parity.trail.ts +26 -0
  145. package/src/trails/pending-force.trail.ts +21 -0
  146. package/src/trails/permit-governance.trail.ts +51 -0
  147. package/src/trails/prefer-schema-inference.trail.ts +21 -0
  148. package/src/trails/public-export-example-coverage.trail.ts +16 -0
  149. package/src/trails/public-internal-deep-imports.trail.ts +94 -0
  150. package/src/trails/public-output-schema.trail.ts +55 -0
  151. package/src/trails/public-union-output-discriminants.trail.ts +33 -0
  152. package/src/trails/read-intent-fires.trail.ts +20 -0
  153. package/src/trails/reference-exists.trail.ts +25 -0
  154. package/src/trails/resolved-import-boundary.trail.ts +109 -0
  155. package/src/trails/resource-declarations.trail.ts +25 -0
  156. package/src/trails/resource-exists.trail.ts +27 -0
  157. package/src/trails/resource-id-grammar.trail.ts +39 -0
  158. package/src/trails/resource-mock-coverage.trail.ts +40 -0
  159. package/src/trails/run.ts +160 -0
  160. package/src/trails/scheduled-destroy-intent.trail.ts +56 -0
  161. package/src/trails/schema.ts +237 -0
  162. package/src/trails/signal-graph-coaching.trail.ts +77 -0
  163. package/src/trails/static-resource-accessor-preference.trail.ts +25 -0
  164. package/src/trails/surface-overlay-coherence.trail.ts +24 -0
  165. package/src/trails/surface-trailhead-coherence.trail.ts +25 -0
  166. package/src/trails/topo.ts +6 -0
  167. package/src/trails/trail-fork-coaching.trail.ts +42 -0
  168. package/src/trails/trailhead-override-divergence.trail.ts +47 -0
  169. package/src/trails/unmaterialized-activation-source.trail.ts +72 -0
  170. package/src/trails/unreachable-detour-shadowing.trail.ts +45 -0
  171. package/src/trails/valid-describe-refs.trail.ts +18 -0
  172. package/src/trails/valid-detour-contract.trail.ts +71 -0
  173. package/src/trails/version-gap.trail.ts +35 -0
  174. package/src/trails/version-pinned-compose.trail.ts +23 -0
  175. package/src/trails/version-without-examples.trail.ts +38 -0
  176. package/src/trails/warden-export-symmetry.trail.ts +16 -0
  177. package/src/trails/warden-rules-use-ast.trail.ts +64 -0
  178. package/src/trails/webhook-route-collision.trail.ts +50 -0
  179. package/src/trails/wrap-rule.ts +224 -0
  180. package/src/workspaces.ts +199 -0
  181. package/.turbo/turbo-build.log +0 -1
  182. package/.turbo/turbo-lint.log +0 -3
  183. package/.turbo/turbo-typecheck.log +0 -1
  184. package/dist/cli.d.ts +0 -46
  185. package/dist/cli.d.ts.map +0 -1
  186. package/dist/cli.js +0 -218
  187. package/dist/cli.js.map +0 -1
  188. package/dist/drift.d.ts +0 -26
  189. package/dist/drift.d.ts.map +0 -1
  190. package/dist/drift.js +0 -27
  191. package/dist/drift.js.map +0 -1
  192. package/dist/formatters.d.ts +0 -29
  193. package/dist/formatters.d.ts.map +0 -1
  194. package/dist/formatters.js +0 -87
  195. package/dist/formatters.js.map +0 -1
  196. package/dist/index.d.ts +0 -26
  197. package/dist/index.d.ts.map +0 -1
  198. package/dist/index.js +0 -26
  199. package/dist/index.js.map +0 -1
  200. package/dist/rules/ast.d.ts +0 -41
  201. package/dist/rules/ast.d.ts.map +0 -1
  202. package/dist/rules/ast.js +0 -161
  203. package/dist/rules/ast.js.map +0 -1
  204. package/dist/rules/context-no-surface-types.d.ts +0 -12
  205. package/dist/rules/context-no-surface-types.d.ts.map +0 -1
  206. package/dist/rules/context-no-surface-types.js +0 -96
  207. package/dist/rules/context-no-surface-types.js.map +0 -1
  208. package/dist/rules/implementation-returns-result.d.ts +0 -13
  209. package/dist/rules/implementation-returns-result.d.ts.map +0 -1
  210. package/dist/rules/implementation-returns-result.js +0 -277
  211. package/dist/rules/implementation-returns-result.js.map +0 -1
  212. package/dist/rules/index.d.ts +0 -15
  213. package/dist/rules/index.d.ts.map +0 -1
  214. package/dist/rules/index.js +0 -34
  215. package/dist/rules/index.js.map +0 -1
  216. package/dist/rules/no-direct-impl-in-route.d.ts +0 -12
  217. package/dist/rules/no-direct-impl-in-route.d.ts.map +0 -1
  218. package/dist/rules/no-direct-impl-in-route.js +0 -47
  219. package/dist/rules/no-direct-impl-in-route.js.map +0 -1
  220. package/dist/rules/no-direct-implementation-call.d.ts +0 -12
  221. package/dist/rules/no-direct-implementation-call.d.ts.map +0 -1
  222. package/dist/rules/no-direct-implementation-call.js +0 -39
  223. package/dist/rules/no-direct-implementation-call.js.map +0 -1
  224. package/dist/rules/no-sync-result-assumption.d.ts +0 -6
  225. package/dist/rules/no-sync-result-assumption.d.ts.map +0 -1
  226. package/dist/rules/no-sync-result-assumption.js +0 -98
  227. package/dist/rules/no-sync-result-assumption.js.map +0 -1
  228. package/dist/rules/no-throw-in-detour-target.d.ts +0 -12
  229. package/dist/rules/no-throw-in-detour-target.d.ts.map +0 -1
  230. package/dist/rules/no-throw-in-detour-target.js +0 -87
  231. package/dist/rules/no-throw-in-detour-target.js.map +0 -1
  232. package/dist/rules/no-throw-in-implementation.d.ts +0 -9
  233. package/dist/rules/no-throw-in-implementation.d.ts.map +0 -1
  234. package/dist/rules/no-throw-in-implementation.js +0 -34
  235. package/dist/rules/no-throw-in-implementation.js.map +0 -1
  236. package/dist/rules/prefer-schema-inference.d.ts +0 -7
  237. package/dist/rules/prefer-schema-inference.d.ts.map +0 -1
  238. package/dist/rules/prefer-schema-inference.js +0 -86
  239. package/dist/rules/prefer-schema-inference.js.map +0 -1
  240. package/dist/rules/scan.d.ts +0 -8
  241. package/dist/rules/scan.d.ts.map +0 -1
  242. package/dist/rules/scan.js +0 -32
  243. package/dist/rules/scan.js.map +0 -1
  244. package/dist/rules/specs.d.ts +0 -29
  245. package/dist/rules/specs.d.ts.map +0 -1
  246. package/dist/rules/specs.js +0 -192
  247. package/dist/rules/specs.js.map +0 -1
  248. package/dist/rules/structure.d.ts +0 -13
  249. package/dist/rules/structure.d.ts.map +0 -1
  250. package/dist/rules/structure.js +0 -142
  251. package/dist/rules/structure.js.map +0 -1
  252. package/dist/rules/types.d.ts +0 -52
  253. package/dist/rules/types.d.ts.map +0 -1
  254. package/dist/rules/types.js +0 -2
  255. package/dist/rules/types.js.map +0 -1
  256. package/dist/rules/valid-describe-refs.d.ts +0 -7
  257. package/dist/rules/valid-describe-refs.d.ts.map +0 -1
  258. package/dist/rules/valid-describe-refs.js +0 -51
  259. package/dist/rules/valid-describe-refs.js.map +0 -1
  260. package/dist/rules/valid-detour-refs.d.ts +0 -6
  261. package/dist/rules/valid-detour-refs.d.ts.map +0 -1
  262. package/dist/rules/valid-detour-refs.js +0 -116
  263. package/dist/rules/valid-detour-refs.js.map +0 -1
  264. package/src/__tests__/cli.test.ts +0 -198
  265. package/src/__tests__/drift.test.ts +0 -74
  266. package/src/__tests__/formatters.test.ts +0 -157
  267. package/src/__tests__/implementation-returns-result.test.ts +0 -129
  268. package/src/__tests__/no-direct-implementation-call.test.ts +0 -83
  269. package/src/__tests__/no-sync-result-assumption.test.ts +0 -85
  270. package/src/__tests__/no-throw-in-detour-target.test.ts +0 -78
  271. package/src/__tests__/prefer-schema-inference.test.ts +0 -84
  272. package/src/__tests__/rules.test.ts +0 -227
  273. package/src/__tests__/valid-describe-refs.test.ts +0 -60
  274. package/src/rules/ast.ts +0 -213
  275. package/src/rules/no-direct-impl-in-route.ts +0 -81
  276. package/src/rules/no-throw-in-detour-target.ts +0 -150
  277. package/src/rules/valid-detour-refs.ts +0 -187
  278. package/tsconfig.json +0 -9
  279. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,633 @@
1
+ import { z } from 'zod';
2
+
3
+ export const governedVocabularyTransitionStatuses = [
4
+ 'planned',
5
+ 'active',
6
+ 'complete',
7
+ ] as const;
8
+
9
+ const governedVocabularySingleTargetSchema = z.object({
10
+ kind: z.literal('single'),
11
+ to: z.string().min(1),
12
+ });
13
+
14
+ const governedVocabularyClassifiedTargetSchema = z.object({
15
+ guidance: z.string().min(1),
16
+ kind: z.literal('classified'),
17
+ options: z
18
+ .array(
19
+ z.object({
20
+ to: z.string().min(1),
21
+ when: z.string().min(1),
22
+ })
23
+ )
24
+ .min(1),
25
+ });
26
+
27
+ export const governedVocabularyTargetSchema = z.discriminatedUnion('kind', [
28
+ governedVocabularySingleTargetSchema,
29
+ governedVocabularyClassifiedTargetSchema,
30
+ ]);
31
+
32
+ export const governedVocabularyPreserveRuleSchema = z.object({
33
+ paths: z.array(z.string().min(1)).optional(),
34
+ pattern: z.string().min(1),
35
+ reason: z.string().min(1),
36
+ });
37
+
38
+ export const governedVocabularyScopeSchema = z.object({
39
+ exclude: z.array(z.string().min(1)).optional(),
40
+ extensions: z.array(z.string().min(1)).optional(),
41
+ ignoredDirectories: z.array(z.string().min(1)).optional(),
42
+ include: z.array(z.string().min(1)).optional(),
43
+ });
44
+
45
+ export const governedVocabularySymbolRenameMatchModes = [
46
+ 'exact',
47
+ 'identifier-segment',
48
+ ] as const;
49
+
50
+ export const governedVocabularySymbolRenameSchema = z.object({
51
+ from: z.string().min(1),
52
+ match: z.enum(governedVocabularySymbolRenameMatchModes).default('exact'),
53
+ reviewDeclarationTypes: z.array(z.string().min(1)).default([]),
54
+ to: z.string().min(1),
55
+ });
56
+
57
+ export const governedVocabularyLiteralRenameSchema = z.object({
58
+ from: z.string().min(1),
59
+ match: z.enum(['exact', 'property-key', 'review']).optional(),
60
+ moduleSpecifier: z
61
+ .object({
62
+ targetPackage: z.string().min(1),
63
+ })
64
+ .optional(),
65
+ to: z.string().min(1),
66
+ });
67
+
68
+ export const governedVocabularyTransitionSchema = z.object({
69
+ codeIdentifiers: z.array(z.string().min(1)).default([]),
70
+ docs: z.object({
71
+ guidance: z.array(z.string().min(1)).default([]),
72
+ summary: z.string().min(1),
73
+ }),
74
+ from: z.string().min(1),
75
+ id: z.string().min(1),
76
+ intent: z.string().min(1),
77
+ kind: z.literal('vocabulary'),
78
+ oldForms: z.array(z.string().min(1)).min(1),
79
+ overrides: z.record(z.string().min(1), z.string().min(1)).default({}),
80
+ preserve: z.array(governedVocabularyPreserveRuleSchema).default([]),
81
+ reviewForms: z.array(z.string().min(1)).default([]),
82
+ safeRewriteForms: z.record(z.string().min(1), z.string().min(1)).default({}),
83
+ scope: governedVocabularyScopeSchema.optional(),
84
+ status: z.enum(governedVocabularyTransitionStatuses),
85
+ stringLiteralRenames: z
86
+ .array(governedVocabularyLiteralRenameSchema)
87
+ .default([]),
88
+ symbolRenames: z.array(governedVocabularySymbolRenameSchema).default([]),
89
+ target: governedVocabularyTargetSchema,
90
+ });
91
+
92
+ export const governedVocabularyRegistrySchema = z
93
+ .array(governedVocabularyTransitionSchema)
94
+ .superRefine((transitions, ctx) => {
95
+ const seenIds = new Set<string>();
96
+ const seenFrom = new Set<string>();
97
+
98
+ for (const [index, transition] of transitions.entries()) {
99
+ if (seenIds.has(transition.id)) {
100
+ ctx.addIssue({
101
+ code: 'custom',
102
+ message: `Duplicate governed vocabulary transition id "${transition.id}".`,
103
+ path: [index, 'id'],
104
+ });
105
+ }
106
+ seenIds.add(transition.id);
107
+
108
+ if (seenFrom.has(transition.from)) {
109
+ ctx.addIssue({
110
+ code: 'custom',
111
+ message: `Duplicate governed vocabulary source "${transition.from}".`,
112
+ path: [index, 'from'],
113
+ });
114
+ }
115
+ seenFrom.add(transition.from);
116
+ }
117
+ });
118
+
119
+ export type GovernedVocabularyPreserveRule = z.output<
120
+ typeof governedVocabularyPreserveRuleSchema
121
+ >;
122
+ export type GovernedVocabularyScope = z.output<
123
+ typeof governedVocabularyScopeSchema
124
+ >;
125
+ export type GovernedVocabularyTarget = z.output<
126
+ typeof governedVocabularyTargetSchema
127
+ >;
128
+ export type GovernedVocabularySymbolRename = z.output<
129
+ typeof governedVocabularySymbolRenameSchema
130
+ >;
131
+ export type GovernedVocabularyLiteralRename = z.output<
132
+ typeof governedVocabularyLiteralRenameSchema
133
+ >;
134
+ export type GovernedVocabularyTransition = z.output<
135
+ typeof governedVocabularyTransitionSchema
136
+ >;
137
+ export type GovernedVocabularyTransitionInput = z.input<
138
+ typeof governedVocabularyTransitionSchema
139
+ >;
140
+
141
+ const defineTransition = (
142
+ input: GovernedVocabularyTransitionInput
143
+ ): GovernedVocabularyTransition =>
144
+ governedVocabularyTransitionSchema.parse(input);
145
+
146
+ const reviewFunctionParamDeclarations = {
147
+ reviewDeclarationTypes: ['FunctionParam'],
148
+ };
149
+
150
+ const v1VocabularyHistoricalExcludes = [
151
+ '.agents/goals/**',
152
+ '**/.agents/goals/**',
153
+ '.agents/memory/**',
154
+ '**/.agents/memory/**',
155
+ '.agents/notes/**',
156
+ '**/.agents/notes/**',
157
+ '.claude/agent-memory/**',
158
+ '**/.claude/agent-memory/**',
159
+ '.agents/plans/archive/**',
160
+ '**/.agents/plans/archive/**',
161
+ '.changeset/**',
162
+ '**/.changeset/**',
163
+ '.scratch/**',
164
+ '**/.scratch/**',
165
+ '.trails/regrade/history/**',
166
+ '**/.trails/regrade/history/**',
167
+ '**/CHANGELOG.md',
168
+ '**/.tmp-tests/**',
169
+ ];
170
+
171
+ const v1VocabularyHistoricalPreservePaths = [
172
+ '.agents/plans/**',
173
+ '**/.agents/plans/**',
174
+ 'docs/adr/0*.md',
175
+ 'docs/adr/decision-map.json',
176
+ 'docs/migration/**',
177
+ 'docs/releases/beta*.md',
178
+ 'docs/releases/v1-vocabulary-reset.md',
179
+ 'docs/releases/v1-vocabulary-transition-workflow.md',
180
+ 'scripts/vocab-cutover-*.ts',
181
+ ];
182
+
183
+ const v1VocabularySelfExcludes = [
184
+ 'packages/warden/src/__tests__/retired-vocabulary.test.ts',
185
+ 'packages/warden/src/rules/retired-vocabulary.ts',
186
+ ];
187
+
188
+ const unique = (values: readonly string[]): string[] => [...new Set(values)];
189
+
190
+ const escapeRegExp = (value: string): string =>
191
+ value.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&');
192
+
193
+ const formsPattern = (forms: readonly string[]): string =>
194
+ `(?:${forms.map(escapeRegExp).join('|')})`;
195
+
196
+ const defineV1Transition = (
197
+ input: GovernedVocabularyTransitionInput
198
+ ): GovernedVocabularyTransition =>
199
+ defineTransition({
200
+ ...input,
201
+ preserve: [
202
+ {
203
+ paths: v1VocabularyHistoricalPreservePaths,
204
+ pattern: formsPattern(
205
+ unique([...(input.oldForms ?? []), ...(input.reviewForms ?? [])])
206
+ ),
207
+ reason:
208
+ 'Preserve authored migration plans and historical decision/release evidence while keeping occurrences visible to the run ledger.',
209
+ },
210
+ ...(input.preserve ?? []),
211
+ ],
212
+ scope: {
213
+ ...input.scope,
214
+ exclude: unique([
215
+ ...v1VocabularyHistoricalExcludes,
216
+ ...v1VocabularySelfExcludes,
217
+ ...(input.scope?.exclude ?? []),
218
+ ]),
219
+ },
220
+ });
221
+
222
+ export const governedVocabularyTransitions =
223
+ governedVocabularyRegistrySchema.parse([
224
+ defineTransition({
225
+ codeIdentifiers: ['ctx.cross', 'crossInput', 'crosses'],
226
+ docs: {
227
+ guidance: [
228
+ 'Exact ctx.cross, crossInput, and crosses forms are mechanically rewritten.',
229
+ 'Broader cross or Cross forms route to review because a text rule cannot prove the intended symbol boundary.',
230
+ ],
231
+ summary:
232
+ 'Beta.19 retired cross composition vocabulary in favor of compose.',
233
+ },
234
+ from: 'cross',
235
+ id: 'cross-compose',
236
+ intent:
237
+ 'Retire beta.19 cross composition vocabulary in favor of compose.',
238
+ kind: 'vocabulary',
239
+ oldForms: ['cross', 'Cross', 'crosses', 'crossInput', 'ctx.cross'],
240
+ reviewForms: ['Cross', 'cross'],
241
+ safeRewriteForms: {
242
+ crossInput: 'composeInput',
243
+ crosses: 'composes',
244
+ 'ctx.cross': 'ctx.compose',
245
+ },
246
+ status: 'complete',
247
+ symbolRenames: [
248
+ { ...reviewFunctionParamDeclarations, from: 'cross', to: 'compose' },
249
+ {
250
+ ...reviewFunctionParamDeclarations,
251
+ from: 'crossInput',
252
+ to: 'composeInput',
253
+ },
254
+ { ...reviewFunctionParamDeclarations, from: 'crosses', to: 'composes' },
255
+ ],
256
+ target: { kind: 'single', to: 'compose' },
257
+ }),
258
+ defineV1Transition({
259
+ codeIdentifiers: ['blaze', 'blazes'],
260
+ docs: {
261
+ guidance: [
262
+ 'Treat code/API identifiers as governed symbols, not prose-only vocabulary.',
263
+ 'Review inflected forms such as blazed or blazing instead of forcing a mechanical rewrite.',
264
+ ],
265
+ summary:
266
+ 'The authored trail behavior field is moving from blaze to implementation.',
267
+ },
268
+ from: 'blaze',
269
+ id: 'v1-blaze-implementation',
270
+ intent:
271
+ 'Move the authored trail behavior field from blaze to implementation for v1.',
272
+ kind: 'vocabulary',
273
+ oldForms: ['blaze', 'blazes', 'Blaze'],
274
+ reviewForms: ['Blaze', 'blazing', 'blazed', 'trailblaze'],
275
+ safeRewriteForms: {
276
+ blaze: 'implementation',
277
+ blazes: 'implementations',
278
+ },
279
+ status: 'complete',
280
+ stringLiteralRenames: [
281
+ { from: 'blaze', match: 'property-key', to: 'implementation' },
282
+ ],
283
+ symbolRenames: [
284
+ {
285
+ ...reviewFunctionParamDeclarations,
286
+ from: 'blaze',
287
+ match: 'identifier-segment',
288
+ to: 'implementation',
289
+ },
290
+ {
291
+ ...reviewFunctionParamDeclarations,
292
+ from: 'blazes',
293
+ to: 'implementations',
294
+ },
295
+ ],
296
+ target: { kind: 'single', to: 'implementation' },
297
+ }),
298
+ defineV1Transition({
299
+ codeIdentifiers: ['contour', 'contours', 'wayfind.contours'],
300
+ docs: {
301
+ guidance: [
302
+ 'Keep domain-object semantics distinct from entities in app data until the occurrence is classified.',
303
+ 'Treat contour code/API identifiers as governed symbols, with FunctionParam shadows routed to review.',
304
+ 'Rewrite exact framework string literals only; prose, substrings, and inflections stay outside mechanical apply.',
305
+ ],
306
+ summary:
307
+ 'The domain object declaration term is moving from contour to entity.',
308
+ },
309
+ from: 'contour',
310
+ id: 'v1-contour-entity',
311
+ intent:
312
+ 'Move the domain object declaration vocabulary from contour to entity for v1.',
313
+ kind: 'vocabulary',
314
+ oldForms: ['contour', 'contours', 'Contour'],
315
+ reviewForms: ['Contour', 'Contours', 'contoured', 'contouring'],
316
+ safeRewriteForms: {
317
+ contour: 'entity',
318
+ contours: 'entities',
319
+ },
320
+ status: 'complete',
321
+ stringLiteralRenames: [
322
+ { from: 'contour', match: 'review', to: 'entity' },
323
+ { from: 'contours', match: 'review', to: 'entities' },
324
+ { from: 'wayfind.contours', to: 'wayfind.entities' },
325
+ ],
326
+ symbolRenames: [
327
+ {
328
+ ...reviewFunctionParamDeclarations,
329
+ from: 'contour',
330
+ match: 'identifier-segment',
331
+ to: 'entity',
332
+ },
333
+ {
334
+ ...reviewFunctionParamDeclarations,
335
+ from: 'contours',
336
+ match: 'identifier-segment',
337
+ to: 'entities',
338
+ },
339
+ ],
340
+ target: { kind: 'single', to: 'entity' },
341
+ }),
342
+ defineV1Transition({
343
+ codeIdentifiers: [
344
+ '@ontrails/topographer',
345
+ '@ontrails/topographer/backend-support',
346
+ '0042-core-topographer-boundary-doctrine',
347
+ 'core-topographer-boundary-doctrine',
348
+ 'Topographer-owned',
349
+ 'packages/topographer',
350
+ 'topographer',
351
+ 'topographers',
352
+ ],
353
+ docs: {
354
+ guidance: [
355
+ 'Treat topographer code/API identifiers as governed symbols, with case and compound forms handled by identifier-segment matching.',
356
+ 'Rewrite only exact package route/module-specifier occurrences; near routes and larger route strings stay untouched.',
357
+ ],
358
+ summary:
359
+ 'The graph artifact package and vocabulary moved from topographer to topography.',
360
+ },
361
+ from: 'topographer',
362
+ id: 'v1-topographer-topography',
363
+ intent:
364
+ 'Move graph artifact package routes and code vocabulary from topographer to topography for v1.',
365
+ kind: 'vocabulary',
366
+ oldForms: [
367
+ '@ontrails/topographer',
368
+ '@ontrails/topographer/backend-support',
369
+ '0042-core-topographer-boundary-doctrine',
370
+ 'core-topographer-boundary-doctrine',
371
+ 'Topographer-owned',
372
+ 'packages/topographer',
373
+ 'topographer',
374
+ 'topographers',
375
+ 'Topographer',
376
+ ],
377
+ reviewForms: ['Topographer'],
378
+ safeRewriteForms: {
379
+ '0042-core-topographer-boundary-doctrine':
380
+ '0042-core-topography-boundary-doctrine',
381
+ '@ontrails/topographer': '@ontrails/topography',
382
+ '@ontrails/topographer/backend-support':
383
+ '@ontrails/topography/backend-support',
384
+ 'Topographer-owned': 'Topography-owned',
385
+ 'core-topographer-boundary-doctrine':
386
+ 'core-topography-boundary-doctrine',
387
+ 'packages/topographer': 'packages/topography',
388
+ topographer: 'topography',
389
+ topographers: 'topographies',
390
+ },
391
+ status: 'complete',
392
+ stringLiteralRenames: [
393
+ {
394
+ from: '@ontrails/topographer',
395
+ moduleSpecifier: { targetPackage: '@ontrails/topography' },
396
+ to: '@ontrails/topography',
397
+ },
398
+ {
399
+ from: '@ontrails/topographer/backend-support',
400
+ moduleSpecifier: { targetPackage: '@ontrails/topography' },
401
+ to: '@ontrails/topography/backend-support',
402
+ },
403
+ {
404
+ from: '0042-core-topographer-boundary-doctrine',
405
+ to: '0042-core-topography-boundary-doctrine',
406
+ },
407
+ {
408
+ from: 'core-topographer-boundary-doctrine',
409
+ to: 'core-topography-boundary-doctrine',
410
+ },
411
+ { from: 'Topographer-owned', to: 'Topography-owned' },
412
+ { from: 'packages/topographer', to: 'packages/topography' },
413
+ ],
414
+ symbolRenames: [
415
+ {
416
+ ...reviewFunctionParamDeclarations,
417
+ from: 'topographer',
418
+ match: 'identifier-segment',
419
+ to: 'topography',
420
+ },
421
+ {
422
+ ...reviewFunctionParamDeclarations,
423
+ from: 'topographers',
424
+ match: 'identifier-segment',
425
+ to: 'topographies',
426
+ },
427
+ ],
428
+ target: { kind: 'single', to: 'topography' },
429
+ }),
430
+ defineV1Transition({
431
+ codeIdentifiers: [
432
+ 'facets',
433
+ 'facetId',
434
+ 'McpSurfaceFacetMap',
435
+ 'surface-facet-coherence',
436
+ 'wayfind.facets',
437
+ ],
438
+ docs: {
439
+ guidance: [
440
+ 'A trailhead is one grouped surface entry fronting several trails while preserving member identity.',
441
+ 'Code/API identifiers remain governed symbols and need structured preservation before broad application.',
442
+ ],
443
+ summary:
444
+ 'The grouped surface entry term is moving from facet to trailhead.',
445
+ },
446
+ from: 'facet',
447
+ id: 'v1-facet-trailhead',
448
+ intent:
449
+ 'Move grouped surface entry vocabulary from facet to trailhead for v1.',
450
+ kind: 'vocabulary',
451
+ oldForms: ['facet', 'facets', 'Facet'],
452
+ reviewForms: ['Facet'],
453
+ safeRewriteForms: {
454
+ facet: 'trailhead',
455
+ facets: 'trailheads',
456
+ },
457
+ status: 'complete',
458
+ stringLiteralRenames: [
459
+ { from: 'surface-facet-coherence', to: 'surface-trailhead-coherence' },
460
+ { from: 'wayfind.facets', to: 'wayfind.trailheads' },
461
+ ],
462
+ symbolRenames: [
463
+ { ...reviewFunctionParamDeclarations, from: 'facet', to: 'trailhead' },
464
+ {
465
+ ...reviewFunctionParamDeclarations,
466
+ from: 'facets',
467
+ to: 'trailheads',
468
+ },
469
+ {
470
+ ...reviewFunctionParamDeclarations,
471
+ from: 'facetId',
472
+ to: 'trailheadId',
473
+ },
474
+ {
475
+ ...reviewFunctionParamDeclarations,
476
+ from: 'McpSurfaceFacetMap',
477
+ to: 'McpSurfaceTrailheadMap',
478
+ },
479
+ ],
480
+ target: { kind: 'single', to: 'trailhead' },
481
+ }),
482
+ defineV1Transition({
483
+ codeIdentifiers: ['@ontrails/warden/ast'],
484
+ docs: {
485
+ guidance: [
486
+ 'Treat the package route as an exact code string and module specifier, not as vocabulary prose or an identifier segment.',
487
+ 'Rewrite only exact string literal/module-specifier occurrences; near routes and larger strings stay untouched.',
488
+ ],
489
+ summary:
490
+ 'The reusable AST helper route moved from @ontrails/warden/ast to @ontrails/source.',
491
+ },
492
+ from: '@ontrails/warden/ast',
493
+ id: 'v1-warden-ast-source',
494
+ intent:
495
+ 'Move reusable AST helper imports from @ontrails/warden/ast to @ontrails/source for v1.',
496
+ kind: 'vocabulary',
497
+ oldForms: ['@ontrails/warden/ast'],
498
+ preserve: [
499
+ {
500
+ paths: [
501
+ 'adapters/commander/src/__tests__/to-commander.test.ts',
502
+ 'apps/trails/src/__tests__/mcp.test.ts',
503
+ 'apps/trails/src/__tests__/regrade.test.ts',
504
+ 'packages/regrade/src/downstream/__tests__/ast-rewrite.test.ts',
505
+ 'packages/regrade/src/downstream/__tests__/vocabulary.test.ts',
506
+ 'packages/warden/src/__tests__/retired-vocabulary.test.ts',
507
+ 'scripts/verify-oxc-resolver-published.ts',
508
+ ],
509
+ pattern: '^@ontrails/warden/ast$',
510
+ reason:
511
+ 'Preserve transition regression fixtures and the intentional negative resolver assertion after the public route is retired.',
512
+ },
513
+ ],
514
+ reviewForms: [],
515
+ safeRewriteForms: {
516
+ '@ontrails/warden/ast': '@ontrails/source',
517
+ },
518
+ status: 'complete',
519
+ stringLiteralRenames: [
520
+ {
521
+ from: '@ontrails/warden/ast',
522
+ moduleSpecifier: { targetPackage: '@ontrails/source' },
523
+ to: '@ontrails/source',
524
+ },
525
+ ],
526
+ target: { kind: 'single', to: '@ontrails/source' },
527
+ }),
528
+ defineV1Transition({
529
+ codeIdentifiers: ['@ontrails/wayfinder'],
530
+ docs: {
531
+ guidance: [
532
+ 'Treat the package route as an exact code string and module specifier, not as Wayfind product vocabulary.',
533
+ 'Rewrite only the exact package route; subpaths, near routes, and larger strings stay untouched for review.',
534
+ ],
535
+ summary:
536
+ 'The Wayfinder package API moved into @ontrails/topography while Wayfind remains the operator-facing product name.',
537
+ },
538
+ from: '@ontrails/wayfinder',
539
+ id: 'v1-wayfinder-topography',
540
+ intent:
541
+ 'Move programmatic Wayfinder imports into @ontrails/topography while preserving Wayfind surface vocabulary.',
542
+ kind: 'vocabulary',
543
+ oldForms: ['@ontrails/wayfinder'],
544
+ reviewForms: [],
545
+ safeRewriteForms: {
546
+ '@ontrails/wayfinder': '@ontrails/topography',
547
+ },
548
+ status: 'complete',
549
+ stringLiteralRenames: [
550
+ {
551
+ from: '@ontrails/wayfinder',
552
+ moduleSpecifier: { targetPackage: '@ontrails/topography' },
553
+ to: '@ontrails/topography',
554
+ },
555
+ ],
556
+ target: { kind: 'single', to: '@ontrails/topography' },
557
+ }),
558
+ defineV1Transition({
559
+ codeIdentifiers: [],
560
+ docs: {
561
+ guidance: [
562
+ 'Use derive for contract-owned fact production.',
563
+ 'Use render for surface- or operator-facing presentation.',
564
+ 'Route every occurrence to review until the stage is classified.',
565
+ ],
566
+ summary: 'Projection vocabulary splits by stage into derive or render.',
567
+ },
568
+ from: 'projection',
569
+ id: 'v1-projection-derive-render',
570
+ intent:
571
+ 'Split projection vocabulary into derive/render by lifecycle stage for v1.',
572
+ kind: 'vocabulary',
573
+ oldForms: ['projection', 'projections', 'project', 'projected'],
574
+ reviewForms: ['projection', 'projections', 'project', 'projected'],
575
+ safeRewriteForms: {},
576
+ status: 'planned',
577
+ target: {
578
+ guidance:
579
+ 'No single replacement is safe. Classify by whether the occurrence produces contract facts or presents derived facts.',
580
+ kind: 'classified',
581
+ options: [
582
+ {
583
+ to: 'derive',
584
+ when: 'The occurrence describes producing contract-owned facts or inferred data from authored inputs.',
585
+ },
586
+ {
587
+ to: 'render',
588
+ when: 'The occurrence describes presenting derived facts through a surface, report, guide, or operator output.',
589
+ },
590
+ ],
591
+ },
592
+ }),
593
+ ]);
594
+
595
+ export const listGovernedVocabularyTransitions =
596
+ (): readonly GovernedVocabularyTransition[] => governedVocabularyTransitions;
597
+
598
+ export const getGovernedVocabularyTransition = (
599
+ id: string
600
+ ): GovernedVocabularyTransition | undefined =>
601
+ governedVocabularyTransitions.find((transition) => transition.id === id);
602
+
603
+ export const requireGovernedVocabularyTransition = (
604
+ id: string
605
+ ): GovernedVocabularyTransition => {
606
+ const transition = getGovernedVocabularyTransition(id);
607
+ if (transition === undefined) {
608
+ throw new Error(`Unknown governed vocabulary transition "${id}".`);
609
+ }
610
+ return transition;
611
+ };
612
+
613
+ export const formatGovernedVocabularyTransitionGuide = (
614
+ transitions: readonly GovernedVocabularyTransition[] = governedVocabularyTransitions
615
+ ): string =>
616
+ transitions
617
+ .map((transition) => {
618
+ const target =
619
+ transition.target.kind === 'single'
620
+ ? transition.target.to
621
+ : transition.target.options
622
+ .map((option) => `${option.to} (${option.when})`)
623
+ .join(' or ');
624
+ const lines = [
625
+ `- ${transition.id}: ${transition.from} -> ${target}`,
626
+ ` - Status: ${transition.status}`,
627
+ ` - Intent: ${transition.intent}`,
628
+ ` - Safe rewrites: ${Object.keys(transition.safeRewriteForms).length}`,
629
+ ` - Review forms: ${transition.reviewForms.join(', ') || 'none'}`,
630
+ ];
631
+ return lines.join('\n');
632
+ })
633
+ .join('\n');