@ontrails/warden 1.0.0-beta.2 → 1.0.0-beta.21

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 (249) hide show
  1. package/CHANGELOG.md +497 -6
  2. package/README.md +77 -26
  3. package/bin/warden.ts +50 -0
  4. package/package.json +27 -5
  5. package/src/adapter-check.ts +136 -0
  6. package/src/ast.ts +28 -0
  7. package/src/cli.ts +1374 -103
  8. package/src/command.ts +953 -0
  9. package/src/config.ts +184 -0
  10. package/src/draft.ts +22 -0
  11. package/src/drift.ts +106 -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 +206 -14
  16. package/src/project-context.ts +163 -0
  17. package/src/resolve.ts +530 -0
  18. package/src/rules/activation-orphan.ts +97 -0
  19. package/src/rules/ast.ts +3176 -85
  20. package/src/rules/circular-refs.ts +154 -0
  21. package/src/rules/composes-declarations.ts +704 -0
  22. package/src/rules/context-no-surface-types.ts +68 -8
  23. package/src/rules/contour-exists.ts +251 -0
  24. package/src/rules/contour-ids.ts +15 -0
  25. package/src/rules/dead-internal-trail.ts +154 -0
  26. package/src/rules/draft-file-marking.ts +160 -0
  27. package/src/rules/draft-visible-debt.ts +87 -0
  28. package/src/rules/error-mapping-completeness.ts +288 -0
  29. package/src/rules/example-valid.ts +401 -0
  30. package/src/rules/fires-declarations.ts +758 -0
  31. package/src/rules/implementation-returns-result.ts +1265 -95
  32. package/src/rules/incomplete-accessor-for-standard-op.ts +272 -0
  33. package/src/rules/incomplete-crud.ts +580 -0
  34. package/src/rules/index.ts +219 -18
  35. package/src/rules/intent-propagation.ts +127 -0
  36. package/src/rules/layer-field-name-drift.ts +96 -0
  37. package/src/rules/metadata.ts +654 -0
  38. package/src/rules/missing-reconcile.ts +98 -0
  39. package/src/rules/missing-visibility.ts +110 -0
  40. package/src/rules/no-destructured-compose.ts +192 -0
  41. package/src/rules/no-dev-permit-in-source.ts +99 -0
  42. package/src/rules/no-direct-implementation-call.ts +7 -7
  43. package/src/rules/no-legacy-layer-imports.ts +211 -0
  44. package/src/rules/no-native-error-result.ts +111 -0
  45. package/src/rules/no-redundant-result-error-wrap.ts +331 -0
  46. package/src/rules/no-retired-cross-vocabulary.ts +194 -0
  47. package/src/rules/no-sync-result-assumption.ts +1134 -99
  48. package/src/rules/no-throw-in-detour-recover.ts +225 -0
  49. package/src/rules/no-throw-in-implementation.ts +10 -9
  50. package/src/rules/no-top-level-surface.ts +389 -0
  51. package/src/rules/on-references-exist.ts +194 -0
  52. package/src/rules/orphaned-signal.ts +150 -0
  53. package/src/rules/owner-projection-parity.ts +146 -0
  54. package/src/rules/permit-governance.ts +25 -0
  55. package/src/rules/public-export-example-coverage.ts +553 -0
  56. package/src/rules/public-internal-deep-imports.ts +517 -0
  57. package/src/rules/public-output-schema.ts +29 -0
  58. package/src/rules/public-union-output-discriminants.ts +150 -0
  59. package/src/rules/read-intent-fires.ts +187 -0
  60. package/src/rules/reference-exists.ts +98 -0
  61. package/src/rules/registry-names.ts +145 -0
  62. package/src/rules/resolved-import-boundary.ts +146 -0
  63. package/src/rules/resource-declarations.ts +704 -0
  64. package/src/rules/resource-exists.ts +179 -0
  65. package/src/rules/resource-id-grammar.ts +65 -0
  66. package/src/rules/resource-mock-coverage.ts +115 -0
  67. package/src/rules/scan.ts +38 -25
  68. package/src/rules/scheduled-destroy-intent.ts +44 -0
  69. package/src/rules/signal-graph-coaching.ts +191 -0
  70. package/src/rules/specs.ts +9 -5
  71. package/src/rules/static-resource-accessor-preference.ts +657 -0
  72. package/src/rules/surface-facet-coherence.ts +370 -0
  73. package/src/rules/trail-versioning-source.ts +1094 -0
  74. package/src/rules/trail-versioning-topo.ts +172 -0
  75. package/src/rules/types.ts +270 -6
  76. package/src/rules/unmaterialized-activation-source.ts +84 -0
  77. package/src/rules/unreachable-detour-shadowing.ts +344 -0
  78. package/src/rules/valid-describe-refs.ts +160 -32
  79. package/src/rules/valid-detour-contract.ts +78 -0
  80. package/src/rules/warden-export-symmetry.ts +533 -0
  81. package/src/rules/warden-rules-use-ast.ts +996 -0
  82. package/src/rules/webhook-route-collision.ts +243 -0
  83. package/src/trails/activation-orphan.trail.ts +84 -0
  84. package/src/trails/circular-refs.trail.ts +29 -0
  85. package/src/trails/composes-declarations.trail.ts +22 -0
  86. package/src/trails/context-no-surface-types.trail.ts +21 -0
  87. package/src/trails/contour-exists.trail.ts +21 -0
  88. package/src/trails/dead-internal-trail.trail.ts +26 -0
  89. package/src/trails/deprecation-without-guidance.trail.ts +21 -0
  90. package/src/trails/draft-file-marking.trail.ts +16 -0
  91. package/src/trails/draft-visible-debt.trail.ts +16 -0
  92. package/src/trails/error-mapping-completeness.trail.ts +29 -0
  93. package/src/trails/example-valid.trail.ts +25 -0
  94. package/src/trails/fires-declarations.trail.ts +23 -0
  95. package/src/trails/fork-without-preserved-blaze.trail.ts +31 -0
  96. package/src/trails/implementation-returns-result.trail.ts +20 -0
  97. package/src/trails/incomplete-accessor-for-standard-op.trail.ts +76 -0
  98. package/src/trails/incomplete-crud.trail.ts +39 -0
  99. package/src/trails/index.ts +78 -0
  100. package/src/trails/intent-propagation.trail.ts +30 -0
  101. package/src/trails/layer-field-name-drift.trail.ts +39 -0
  102. package/src/trails/marker-schema-unsupported.trail.ts +23 -0
  103. package/src/trails/missing-reconcile.trail.ts +33 -0
  104. package/src/trails/missing-visibility.trail.ts +22 -0
  105. package/src/trails/no-destructured-compose.trail.ts +44 -0
  106. package/src/trails/no-dev-permit-in-source.trail.ts +16 -0
  107. package/src/trails/no-direct-implementation-call.trail.ts +16 -0
  108. package/src/trails/no-legacy-layer-imports.trail.ts +41 -0
  109. package/src/trails/no-native-error-result.trail.ts +18 -0
  110. package/src/trails/no-redundant-result-error-wrap.trail.ts +55 -0
  111. package/src/trails/no-retired-cross-vocabulary.trail.ts +42 -0
  112. package/src/trails/no-sync-result-assumption.trail.ts +19 -0
  113. package/src/trails/no-throw-in-detour-recover.trail.ts +24 -0
  114. package/src/trails/no-throw-in-implementation.trail.ts +20 -0
  115. package/src/trails/no-top-level-surface.trail.ts +43 -0
  116. package/src/trails/on-references-exist.trail.ts +21 -0
  117. package/src/trails/orphaned-signal.trail.ts +36 -0
  118. package/src/trails/owner-projection-parity.trail.ts +26 -0
  119. package/src/trails/pending-force.trail.ts +21 -0
  120. package/src/trails/permit-governance.trail.ts +51 -0
  121. package/src/trails/prefer-schema-inference.trail.ts +21 -0
  122. package/src/trails/public-export-example-coverage.trail.ts +16 -0
  123. package/src/trails/public-internal-deep-imports.trail.ts +94 -0
  124. package/src/trails/public-output-schema.trail.ts +55 -0
  125. package/src/trails/public-union-output-discriminants.trail.ts +33 -0
  126. package/src/trails/read-intent-fires.trail.ts +20 -0
  127. package/src/trails/reference-exists.trail.ts +25 -0
  128. package/src/trails/resolved-import-boundary.trail.ts +109 -0
  129. package/src/trails/resource-declarations.trail.ts +25 -0
  130. package/src/trails/resource-exists.trail.ts +27 -0
  131. package/src/trails/resource-id-grammar.trail.ts +39 -0
  132. package/src/trails/resource-mock-coverage.trail.ts +40 -0
  133. package/src/trails/run.ts +162 -0
  134. package/src/trails/scheduled-destroy-intent.trail.ts +56 -0
  135. package/src/trails/schema.ts +194 -0
  136. package/src/trails/signal-graph-coaching.trail.ts +77 -0
  137. package/src/trails/static-resource-accessor-preference.trail.ts +25 -0
  138. package/src/trails/surface-facet-coherence.trail.ts +25 -0
  139. package/src/trails/topo.ts +6 -0
  140. package/src/trails/unmaterialized-activation-source.trail.ts +72 -0
  141. package/src/trails/unreachable-detour-shadowing.trail.ts +45 -0
  142. package/src/trails/valid-describe-refs.trail.ts +18 -0
  143. package/src/trails/valid-detour-contract.trail.ts +71 -0
  144. package/src/trails/version-gap.trail.ts +35 -0
  145. package/src/trails/version-pinned-compose.trail.ts +23 -0
  146. package/src/trails/version-without-examples.trail.ts +38 -0
  147. package/src/trails/warden-export-symmetry.trail.ts +16 -0
  148. package/src/trails/warden-rules-use-ast.trail.ts +45 -0
  149. package/src/trails/webhook-route-collision.trail.ts +50 -0
  150. package/src/trails/wrap-rule.ts +213 -0
  151. package/src/workspaces.ts +238 -0
  152. package/.turbo/turbo-build.log +0 -1
  153. package/.turbo/turbo-lint.log +0 -3
  154. package/.turbo/turbo-typecheck.log +0 -1
  155. package/dist/cli.d.ts +0 -46
  156. package/dist/cli.d.ts.map +0 -1
  157. package/dist/cli.js +0 -221
  158. package/dist/cli.js.map +0 -1
  159. package/dist/drift.d.ts +0 -26
  160. package/dist/drift.d.ts.map +0 -1
  161. package/dist/drift.js +0 -27
  162. package/dist/drift.js.map +0 -1
  163. package/dist/formatters.d.ts +0 -29
  164. package/dist/formatters.d.ts.map +0 -1
  165. package/dist/formatters.js +0 -87
  166. package/dist/formatters.js.map +0 -1
  167. package/dist/index.d.ts +0 -26
  168. package/dist/index.d.ts.map +0 -1
  169. package/dist/index.js +0 -26
  170. package/dist/index.js.map +0 -1
  171. package/dist/rules/ast.d.ts +0 -41
  172. package/dist/rules/ast.d.ts.map +0 -1
  173. package/dist/rules/ast.js +0 -163
  174. package/dist/rules/ast.js.map +0 -1
  175. package/dist/rules/context-no-surface-types.d.ts +0 -12
  176. package/dist/rules/context-no-surface-types.d.ts.map +0 -1
  177. package/dist/rules/context-no-surface-types.js +0 -96
  178. package/dist/rules/context-no-surface-types.js.map +0 -1
  179. package/dist/rules/implementation-returns-result.d.ts +0 -13
  180. package/dist/rules/implementation-returns-result.d.ts.map +0 -1
  181. package/dist/rules/implementation-returns-result.js +0 -231
  182. package/dist/rules/implementation-returns-result.js.map +0 -1
  183. package/dist/rules/index.d.ts +0 -22
  184. package/dist/rules/index.d.ts.map +0 -1
  185. package/dist/rules/index.js +0 -41
  186. package/dist/rules/index.js.map +0 -1
  187. package/dist/rules/no-direct-impl-in-route.d.ts +0 -12
  188. package/dist/rules/no-direct-impl-in-route.d.ts.map +0 -1
  189. package/dist/rules/no-direct-impl-in-route.js +0 -46
  190. package/dist/rules/no-direct-impl-in-route.js.map +0 -1
  191. package/dist/rules/no-direct-implementation-call.d.ts +0 -12
  192. package/dist/rules/no-direct-implementation-call.d.ts.map +0 -1
  193. package/dist/rules/no-direct-implementation-call.js +0 -39
  194. package/dist/rules/no-direct-implementation-call.js.map +0 -1
  195. package/dist/rules/no-sync-result-assumption.d.ts +0 -6
  196. package/dist/rules/no-sync-result-assumption.d.ts.map +0 -1
  197. package/dist/rules/no-sync-result-assumption.js +0 -98
  198. package/dist/rules/no-sync-result-assumption.js.map +0 -1
  199. package/dist/rules/no-throw-in-detour-target.d.ts +0 -12
  200. package/dist/rules/no-throw-in-detour-target.d.ts.map +0 -1
  201. package/dist/rules/no-throw-in-detour-target.js +0 -87
  202. package/dist/rules/no-throw-in-detour-target.js.map +0 -1
  203. package/dist/rules/no-throw-in-implementation.d.ts +0 -9
  204. package/dist/rules/no-throw-in-implementation.d.ts.map +0 -1
  205. package/dist/rules/no-throw-in-implementation.js +0 -34
  206. package/dist/rules/no-throw-in-implementation.js.map +0 -1
  207. package/dist/rules/prefer-schema-inference.d.ts +0 -7
  208. package/dist/rules/prefer-schema-inference.d.ts.map +0 -1
  209. package/dist/rules/prefer-schema-inference.js +0 -86
  210. package/dist/rules/prefer-schema-inference.js.map +0 -1
  211. package/dist/rules/scan.d.ts +0 -8
  212. package/dist/rules/scan.d.ts.map +0 -1
  213. package/dist/rules/scan.js +0 -32
  214. package/dist/rules/scan.js.map +0 -1
  215. package/dist/rules/specs.d.ts +0 -29
  216. package/dist/rules/specs.d.ts.map +0 -1
  217. package/dist/rules/specs.js +0 -192
  218. package/dist/rules/specs.js.map +0 -1
  219. package/dist/rules/structure.d.ts +0 -13
  220. package/dist/rules/structure.d.ts.map +0 -1
  221. package/dist/rules/structure.js +0 -142
  222. package/dist/rules/structure.js.map +0 -1
  223. package/dist/rules/types.d.ts +0 -52
  224. package/dist/rules/types.d.ts.map +0 -1
  225. package/dist/rules/types.js +0 -2
  226. package/dist/rules/types.js.map +0 -1
  227. package/dist/rules/valid-describe-refs.d.ts +0 -7
  228. package/dist/rules/valid-describe-refs.d.ts.map +0 -1
  229. package/dist/rules/valid-describe-refs.js +0 -51
  230. package/dist/rules/valid-describe-refs.js.map +0 -1
  231. package/dist/rules/valid-detour-refs.d.ts +0 -6
  232. package/dist/rules/valid-detour-refs.d.ts.map +0 -1
  233. package/dist/rules/valid-detour-refs.js +0 -116
  234. package/dist/rules/valid-detour-refs.js.map +0 -1
  235. package/src/__tests__/cli.test.ts +0 -198
  236. package/src/__tests__/drift.test.ts +0 -74
  237. package/src/__tests__/formatters.test.ts +0 -157
  238. package/src/__tests__/implementation-returns-result.test.ts +0 -75
  239. package/src/__tests__/no-direct-implementation-call.test.ts +0 -83
  240. package/src/__tests__/no-sync-result-assumption.test.ts +0 -85
  241. package/src/__tests__/no-throw-in-detour-target.test.ts +0 -78
  242. package/src/__tests__/prefer-schema-inference.test.ts +0 -84
  243. package/src/__tests__/rules.test.ts +0 -188
  244. package/src/__tests__/valid-describe-refs.test.ts +0 -60
  245. package/src/rules/no-direct-impl-in-route.ts +0 -77
  246. package/src/rules/no-throw-in-detour-target.ts +0 -150
  247. package/src/rules/valid-detour-refs.ts +0 -187
  248. package/tsconfig.json +0 -9
  249. package/tsconfig.tsbuildinfo +0 -1
@@ -1,54 +1,255 @@
1
+ import { activationOrphan } from './activation-orphan.js';
2
+ import { circularRefs } from './circular-refs.js';
3
+ import { contourExists } from './contour-exists.js';
1
4
  import { contextNoSurfaceTypes } from './context-no-surface-types.js';
5
+ import { composesDeclarations } from './composes-declarations.js';
6
+ import { deadInternalTrail } from './dead-internal-trail.js';
7
+ import { draftFileMarking } from './draft-file-marking.js';
8
+ import { draftVisibleDebt } from './draft-visible-debt.js';
9
+ import { errorMappingCompleteness } from './error-mapping-completeness.js';
10
+ import { exampleValid } from './example-valid.js';
11
+ import { firesDeclarations } from './fires-declarations.js';
2
12
  import { implementationReturnsResult } from './implementation-returns-result.js';
3
- import { noDirectImplInRoute } from './no-direct-impl-in-route.js';
13
+ import { incompleteAccessorForStandardOp } from './incomplete-accessor-for-standard-op.js';
14
+ import { incompleteCrud } from './incomplete-crud.js';
15
+ import { intentPropagation } from './intent-propagation.js';
16
+ import { layerFieldNameDrift } from './layer-field-name-drift.js';
17
+ import { missingVisibility } from './missing-visibility.js';
18
+ import { missingReconcile } from './missing-reconcile.js';
19
+ import { noDevPermitInSource } from './no-dev-permit-in-source.js';
20
+ import { noDestructuredCompose } from './no-destructured-compose.js';
21
+ import { noLegacyLayerImports } from './no-legacy-layer-imports.js';
4
22
  import { noDirectImplementationCall } from './no-direct-implementation-call.js';
23
+ import { noNativeErrorResult } from './no-native-error-result.js';
24
+ import { noRedundantResultErrorWrap } from './no-redundant-result-error-wrap.js';
25
+ import { noRetiredCrossVocabulary } from './no-retired-cross-vocabulary.js';
5
26
  import { noSyncResultAssumption } from './no-sync-result-assumption.js';
6
- import { noThrowInDetourTarget } from './no-throw-in-detour-target.js';
27
+ import { noThrowInDetourRecover } from './no-throw-in-detour-recover.js';
7
28
  import { noThrowInImplementation } from './no-throw-in-implementation.js';
29
+ import { noTopLevelSurface } from './no-top-level-surface.js';
30
+ import { onReferencesExist } from './on-references-exist.js';
31
+ import { orphanedSignal } from './orphaned-signal.js';
32
+ import { ownerProjectionParity } from './owner-projection-parity.js';
33
+ import { permitGovernance } from './permit-governance.js';
8
34
  import { preferSchemaInference } from './prefer-schema-inference.js';
9
- import type { WardenRule } from './types.js';
35
+ import { publicExportExampleCoverage } from './public-export-example-coverage.js';
36
+ import { publicInternalDeepImports } from './public-internal-deep-imports.js';
37
+ import { publicOutputSchema } from './public-output-schema.js';
38
+ import { publicUnionOutputDiscriminants } from './public-union-output-discriminants.js';
39
+ import { readIntentFires } from './read-intent-fires.js';
40
+ import { referenceExists } from './reference-exists.js';
41
+ import { resolvedImportBoundary } from './resolved-import-boundary.js';
42
+ import { resourceDeclarations } from './resource-declarations.js';
43
+ import { resourceExists } from './resource-exists.js';
44
+ import { resourceIdGrammar } from './resource-id-grammar.js';
45
+ import { resourceMockCoverage } from './resource-mock-coverage.js';
46
+ import { scheduledDestroyIntent } from './scheduled-destroy-intent.js';
47
+ import { signalGraphCoaching } from './signal-graph-coaching.js';
48
+ import { staticResourceAccessorPreference } from './static-resource-accessor-preference.js';
49
+ import { surfaceFacetCoherence } from './surface-facet-coherence.js';
50
+ import {
51
+ forkWithoutPreservedBlaze,
52
+ markerSchemaUnsupported,
53
+ versionPinnedCompose,
54
+ } from './trail-versioning-source.js';
55
+ import {
56
+ deprecationWithoutGuidance,
57
+ pendingForce,
58
+ versionGap,
59
+ versionWithoutExamples,
60
+ } from './trail-versioning-topo.js';
61
+ import type { TopoAwareWardenRule, WardenRule } from './types.js';
62
+ import { unmaterializedActivationSource } from './unmaterialized-activation-source.js';
63
+ import { unreachableDetourShadowing } from './unreachable-detour-shadowing.js';
64
+ import { validDetourContract } from './valid-detour-contract.js';
10
65
  import { validDescribeRefs } from './valid-describe-refs.js';
11
- import { validDetourRefs } from './valid-detour-refs.js';
66
+ import { wardenExportSymmetry } from './warden-export-symmetry.js';
67
+ import { wardenRulesUseAst } from './warden-rules-use-ast.js';
68
+ import { webhookRouteCollision } from './webhook-route-collision.js';
12
69
 
13
70
  export type {
71
+ WardenFix,
72
+ WardenFixCapability,
73
+ WardenFixClass,
74
+ WardenFixEdit,
75
+ WardenFixSafety,
76
+ WardenGuidance,
77
+ WardenGuidanceLink,
78
+ WardenRuleLifecycle,
79
+ WardenRuleLifecycleState,
80
+ WardenRuleConcern,
81
+ WardenRuleMetadata,
82
+ WardenRuleScope,
14
83
  ProjectAwareWardenRule,
15
84
  ProjectContext,
85
+ TopoAwareWardenRule,
16
86
  WardenDiagnostic,
17
87
  WardenRule,
88
+ WardenRuleTier,
18
89
  WardenSeverity,
19
90
  } from './types.js';
20
91
 
92
+ export {
93
+ builtinWardenRuleMetadata,
94
+ getWardenRuleMetadata,
95
+ listWardenRuleMetadata,
96
+ wardenFixClasses,
97
+ wardenFixSafeties,
98
+ wardenRuleConcerns,
99
+ wardenRuleLifecycleStates,
100
+ wardenRuleScopes,
101
+ wardenRuleTiers,
102
+ } from './metadata.js';
103
+ export type { BuiltinWardenRuleName } from './metadata.js';
104
+
105
+ export { activationOrphan } from './activation-orphan.js';
21
106
  export { noThrowInImplementation } from './no-throw-in-implementation.js';
107
+ export { circularRefs } from './circular-refs.js';
108
+ export { contourExists } from './contour-exists.js';
22
109
  export { contextNoSurfaceTypes } from './context-no-surface-types.js';
23
- export { validDetourRefs } from './valid-detour-refs.js';
24
- export { noDirectImplInRoute } from './no-direct-impl-in-route.js';
110
+ export { composesDeclarations } from './composes-declarations.js';
111
+ export { deadInternalTrail } from './dead-internal-trail.js';
112
+ export { draftFileMarking } from './draft-file-marking.js';
113
+ export { draftVisibleDebt } from './draft-visible-debt.js';
114
+ export { errorMappingCompleteness } from './error-mapping-completeness.js';
115
+ export { exampleValid } from './example-valid.js';
116
+ export { firesDeclarations } from './fires-declarations.js';
117
+ export { incompleteAccessorForStandardOp } from './incomplete-accessor-for-standard-op.js';
118
+ export { incompleteCrud } from './incomplete-crud.js';
119
+ export { intentPropagation } from './intent-propagation.js';
120
+ export { layerFieldNameDrift } from './layer-field-name-drift.js';
121
+ export { missingVisibility } from './missing-visibility.js';
122
+ export { missingReconcile } from './missing-reconcile.js';
123
+ export { onReferencesExist } from './on-references-exist.js';
124
+ export { noDevPermitInSource } from './no-dev-permit-in-source.js';
125
+ export { noDestructuredCompose } from './no-destructured-compose.js';
126
+ export { noLegacyLayerImports } from './no-legacy-layer-imports.js';
25
127
  export { noDirectImplementationCall } from './no-direct-implementation-call.js';
128
+ export { noNativeErrorResult } from './no-native-error-result.js';
129
+ export { noRedundantResultErrorWrap } from './no-redundant-result-error-wrap.js';
130
+ export { noRetiredCrossVocabulary } from './no-retired-cross-vocabulary.js';
26
131
  export { noSyncResultAssumption } from './no-sync-result-assumption.js';
27
132
  export { implementationReturnsResult } from './implementation-returns-result.js';
28
- export { noThrowInDetourTarget } from './no-throw-in-detour-target.js';
133
+ export { noThrowInDetourRecover } from './no-throw-in-detour-recover.js';
134
+ export { noTopLevelSurface } from './no-top-level-surface.js';
135
+ export { orphanedSignal } from './orphaned-signal.js';
136
+ export { ownerProjectionParity } from './owner-projection-parity.js';
137
+ export { permitGovernance } from './permit-governance.js';
29
138
  export { preferSchemaInference } from './prefer-schema-inference.js';
139
+ export { publicInternalDeepImports } from './public-internal-deep-imports.js';
140
+ export { publicOutputSchema } from './public-output-schema.js';
141
+ export { publicUnionOutputDiscriminants } from './public-union-output-discriminants.js';
142
+ export { readIntentFires } from './read-intent-fires.js';
143
+ export { referenceExists } from './reference-exists.js';
144
+ export { resolvedImportBoundary } from './resolved-import-boundary.js';
145
+ export { resourceDeclarations } from './resource-declarations.js';
146
+ export { resourceExists } from './resource-exists.js';
147
+ export { resourceIdGrammar } from './resource-id-grammar.js';
148
+ export { resourceMockCoverage } from './resource-mock-coverage.js';
149
+ export { scheduledDestroyIntent } from './scheduled-destroy-intent.js';
150
+ export { signalGraphCoaching } from './signal-graph-coaching.js';
151
+ export { staticResourceAccessorPreference } from './static-resource-accessor-preference.js';
152
+ export { surfaceFacetCoherence } from './surface-facet-coherence.js';
153
+ export {
154
+ forkWithoutPreservedBlaze,
155
+ markerSchemaUnsupported,
156
+ versionPinnedCompose,
157
+ } from './trail-versioning-source.js';
158
+ export {
159
+ deprecationWithoutGuidance,
160
+ pendingForce,
161
+ versionGap,
162
+ versionWithoutExamples,
163
+ } from './trail-versioning-topo.js';
164
+ export { unmaterializedActivationSource } from './unmaterialized-activation-source.js';
165
+ export { unreachableDetourShadowing } from './unreachable-detour-shadowing.js';
166
+ export { validDetourContract } from './valid-detour-contract.js';
30
167
  export { validDescribeRefs } from './valid-describe-refs.js';
168
+ export { webhookRouteCollision } from './webhook-route-collision.js';
31
169
 
32
- /**
33
- * All built-in warden rules, keyed by rule name.
34
- *
35
- * Rules that duplicate validateTopo checks (follows-trails-exist,
36
- * no-recursive-follows, event-origins-exist, examples-match-schema,
37
- * require-output-schema) and follows-matches-calls (now covered by
38
- * testExamples follows coverage) have been removed.
39
- */
170
+ /** All built-in warden rules, keyed by rule name. */
40
171
  export const wardenRules: ReadonlyMap<string, WardenRule> = new Map<
41
172
  string,
42
173
  WardenRule
43
174
  >([
44
175
  [noThrowInImplementation.name, noThrowInImplementation],
176
+ [circularRefs.name, circularRefs],
177
+ [contourExists.name, contourExists],
45
178
  [contextNoSurfaceTypes.name, contextNoSurfaceTypes],
179
+ [composesDeclarations.name, composesDeclarations],
180
+ [deadInternalTrail.name, deadInternalTrail],
181
+ [draftFileMarking.name, draftFileMarking],
182
+ [draftVisibleDebt.name, draftVisibleDebt],
183
+ [errorMappingCompleteness.name, errorMappingCompleteness],
184
+ [exampleValid.name, exampleValid],
185
+ [firesDeclarations.name, firesDeclarations],
186
+ [incompleteCrud.name, incompleteCrud],
187
+ [intentPropagation.name, intentPropagation],
188
+ [layerFieldNameDrift.name, layerFieldNameDrift],
189
+ [missingVisibility.name, missingVisibility],
190
+ [missingReconcile.name, missingReconcile],
191
+ [onReferencesExist.name, onReferencesExist],
192
+ [orphanedSignal.name, orphanedSignal],
193
+ [ownerProjectionParity.name, ownerProjectionParity],
194
+ [publicExportExampleCoverage.name, publicExportExampleCoverage],
195
+ [publicInternalDeepImports.name, publicInternalDeepImports],
196
+ [resourceDeclarations.name, resourceDeclarations],
197
+ [readIntentFires.name, readIntentFires],
198
+ [referenceExists.name, referenceExists],
199
+ [resolvedImportBoundary.name, resolvedImportBoundary],
200
+ [resourceIdGrammar.name, resourceIdGrammar],
201
+ [resourceExists.name, resourceExists],
202
+ [resourceMockCoverage.name, resourceMockCoverage],
46
203
  [preferSchemaInference.name, preferSchemaInference],
204
+ [staticResourceAccessorPreference.name, staticResourceAccessorPreference],
205
+ [surfaceFacetCoherence.name, surfaceFacetCoherence],
47
206
  [validDescribeRefs.name, validDescribeRefs],
48
- [validDetourRefs.name, validDetourRefs],
207
+ [noDevPermitInSource.name, noDevPermitInSource],
208
+ [noDestructuredCompose.name, noDestructuredCompose],
49
209
  [noDirectImplementationCall.name, noDirectImplementationCall],
210
+ [noLegacyLayerImports.name, noLegacyLayerImports],
211
+ [noNativeErrorResult.name, noNativeErrorResult],
212
+ [noRedundantResultErrorWrap.name, noRedundantResultErrorWrap],
213
+ [noRetiredCrossVocabulary.name, noRetiredCrossVocabulary],
50
214
  [noSyncResultAssumption.name, noSyncResultAssumption],
51
215
  [implementationReturnsResult.name, implementationReturnsResult],
52
- [noThrowInDetourTarget.name, noThrowInDetourTarget],
53
- [noDirectImplInRoute.name, noDirectImplInRoute],
216
+ [noThrowInDetourRecover.name, noThrowInDetourRecover],
217
+ [noTopLevelSurface.name, noTopLevelSurface],
218
+ [unreachableDetourShadowing.name, unreachableDetourShadowing],
219
+ [wardenExportSymmetry.name, wardenExportSymmetry],
220
+ [wardenRulesUseAst.name, wardenRulesUseAst],
221
+ [forkWithoutPreservedBlaze.name, forkWithoutPreservedBlaze],
222
+ [markerSchemaUnsupported.name, markerSchemaUnsupported],
223
+ [versionPinnedCompose.name, versionPinnedCompose],
54
224
  ]);
225
+
226
+ /**
227
+ * Built-in topo-aware warden rules, keyed by rule name.
228
+ *
229
+ * These rules inspect the compiled runtime trail graph once per topo,
230
+ * rather than scanning source files. Kept in a separate registry because
231
+ * their dispatch shape differs from `WardenRule` / `ProjectAwareWardenRule`.
232
+ *
233
+ * @remarks
234
+ * Topo-aware rules only fire when the warden runtime is invoked with a
235
+ * resolved `Topo` (see `WardenOptions.topo`). Runs without a topo — e.g.
236
+ * pure source-directory lints — silently skip this registry. Rules
237
+ * registered here must tolerate non-execution when no topo is available.
238
+ */
239
+ export const wardenTopoRules: ReadonlyMap<string, TopoAwareWardenRule> =
240
+ new Map<string, TopoAwareWardenRule>([
241
+ [activationOrphan.name, activationOrphan],
242
+ [incompleteAccessorForStandardOp.name, incompleteAccessorForStandardOp],
243
+ [permitGovernance.name, permitGovernance],
244
+ [publicOutputSchema.name, publicOutputSchema],
245
+ [publicUnionOutputDiscriminants.name, publicUnionOutputDiscriminants],
246
+ [scheduledDestroyIntent.name, scheduledDestroyIntent],
247
+ [signalGraphCoaching.name, signalGraphCoaching],
248
+ [unmaterializedActivationSource.name, unmaterializedActivationSource],
249
+ [validDetourContract.name, validDetourContract],
250
+ [deprecationWithoutGuidance.name, deprecationWithoutGuidance],
251
+ [pendingForce.name, pendingForce],
252
+ [versionGap.name, versionGap],
253
+ [versionWithoutExamples.name, versionWithoutExamples],
254
+ [webhookRouteCollision.name, webhookRouteCollision],
255
+ ]);
@@ -0,0 +1,127 @@
1
+ import type { Intent } from '@ontrails/core';
2
+ import {
3
+ collectNamedTrailIds,
4
+ collectTrailIntentsById,
5
+ extractDefinitionComposeTargetIds,
6
+ findTrailDefinitions,
7
+ offsetToLine,
8
+ parse,
9
+ } from './ast.js';
10
+ import type { AstNode } from './ast.js';
11
+ import { isTestFile } from './scan.js';
12
+ import type {
13
+ ProjectAwareWardenRule,
14
+ ProjectContext,
15
+ WardenDiagnostic,
16
+ } from './types.js';
17
+
18
+ const buildIntentPropagationDiagnostic = (
19
+ trailId: string,
20
+ targetTrailId: string,
21
+ targetIntent: Exclude<Intent, 'read'>,
22
+ filePath: string,
23
+ line: number
24
+ ): WardenDiagnostic => ({
25
+ filePath,
26
+ line,
27
+ message: `Trail "${trailId}" declares intent: 'read' but composes "${targetTrailId}" with intent: '${targetIntent}'. Read trails must not compose write or destroy side effects.`,
28
+ rule: 'intent-propagation',
29
+ severity: 'warn',
30
+ });
31
+
32
+ const buildDiagnosticsForComposeTargets = (
33
+ trailId: string,
34
+ targetTrailIds: readonly string[],
35
+ filePath: string,
36
+ line: number,
37
+ trailIntentsById: ReadonlyMap<string, Intent>
38
+ ): readonly WardenDiagnostic[] =>
39
+ targetTrailIds.flatMap((targetTrailId) => {
40
+ const targetIntent = trailIntentsById.get(targetTrailId);
41
+ if (!targetIntent || targetIntent === 'read') {
42
+ return [];
43
+ }
44
+
45
+ return [
46
+ buildIntentPropagationDiagnostic(
47
+ trailId,
48
+ targetTrailId,
49
+ targetIntent,
50
+ filePath,
51
+ line
52
+ ),
53
+ ];
54
+ });
55
+
56
+ const buildDiagnosticsForTrail = (
57
+ def: ReturnType<typeof findTrailDefinitions>[number],
58
+ sourceCode: string,
59
+ filePath: string,
60
+ namedTrailIds: ReadonlyMap<string, string>,
61
+ trailIntentsById: ReadonlyMap<string, Intent>
62
+ ): readonly WardenDiagnostic[] => {
63
+ if (def.kind !== 'trail' || trailIntentsById.get(def.id) !== 'read') {
64
+ return [];
65
+ }
66
+
67
+ return buildDiagnosticsForComposeTargets(
68
+ def.id,
69
+ extractDefinitionComposeTargetIds(def.config, sourceCode, namedTrailIds),
70
+ filePath,
71
+ offsetToLine(sourceCode, def.start),
72
+ trailIntentsById
73
+ );
74
+ };
75
+
76
+ const checkIntentPropagation = (
77
+ ast: AstNode | null,
78
+ sourceCode: string,
79
+ filePath: string,
80
+ trailIntentsById: ReadonlyMap<string, Intent>
81
+ ): readonly WardenDiagnostic[] => {
82
+ if (isTestFile(filePath) || !ast) {
83
+ return [];
84
+ }
85
+
86
+ const namedTrailIds = collectNamedTrailIds(ast);
87
+ return findTrailDefinitions(ast).flatMap((def) =>
88
+ buildDiagnosticsForTrail(
89
+ def,
90
+ sourceCode,
91
+ filePath,
92
+ namedTrailIds,
93
+ trailIntentsById
94
+ )
95
+ );
96
+ };
97
+
98
+ export const intentPropagation: ProjectAwareWardenRule = {
99
+ check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
100
+ const ast = parse(filePath, sourceCode);
101
+ return checkIntentPropagation(
102
+ ast,
103
+ sourceCode,
104
+ filePath,
105
+ ast ? collectTrailIntentsById(ast) : new Map<string, Intent>()
106
+ );
107
+ },
108
+ checkWithContext(
109
+ sourceCode: string,
110
+ filePath: string,
111
+ context: ProjectContext
112
+ ): readonly WardenDiagnostic[] {
113
+ const ast = parse(filePath, sourceCode);
114
+ const localTrailIntentsById = ast
115
+ ? collectTrailIntentsById(ast)
116
+ : new Map<string, Intent>();
117
+ const trailIntentsById = new Map(localTrailIntentsById);
118
+ for (const [trailId, intent] of context.trailIntentsById ?? []) {
119
+ trailIntentsById.set(trailId, intent);
120
+ }
121
+ return checkIntentPropagation(ast, sourceCode, filePath, trailIntentsById);
122
+ },
123
+ description:
124
+ "Warn when a trail declaring intent: 'read' composes a trail whose normalized intent is write or destroy.",
125
+ name: 'intent-propagation',
126
+ severity: 'warn',
127
+ };
@@ -0,0 +1,96 @@
1
+ import { sep } from 'node:path';
2
+
3
+ import { identifierName, offsetToLine, parse, walk } from './ast.js';
4
+ import type { AstNode } from './ast.js';
5
+ import type { WardenDiagnostic, WardenRule } from './types.js';
6
+
7
+ const RULE_NAME = 'layer-field-name-drift';
8
+
9
+ const LEGACY_RESERVED_SET_NAMES = new Set(['META_FLAG_CANDIDATES']);
10
+
11
+ const normalizePath = (filePath: string): string =>
12
+ filePath.split(sep).join('/');
13
+
14
+ const isSurfaceSourceFile = (filePath: string): boolean => {
15
+ const normalized = normalizePath(filePath);
16
+ return /(^|\/)packages\/(cli|http|mcp)\/src\//.test(normalized);
17
+ };
18
+
19
+ const isTestFile = (filePath: string): boolean => {
20
+ const normalized = normalizePath(filePath);
21
+ return (
22
+ normalized.includes('/__tests__/') || /\.test\.[cm]?tsx?$/.test(normalized)
23
+ );
24
+ };
25
+
26
+ const looksLikeLayerReservedNameSet = (name: string): boolean => {
27
+ const lower = name.toLowerCase();
28
+ return (
29
+ LEGACY_RESERVED_SET_NAMES.has(name) ||
30
+ (lower.includes('layer') &&
31
+ lower.includes('reserved') &&
32
+ (lower.includes('name') || lower.includes('flag')))
33
+ );
34
+ };
35
+
36
+ const isSetConstruction = (node: AstNode | undefined): boolean => {
37
+ if (node?.type !== 'NewExpression') {
38
+ return false;
39
+ }
40
+ const { callee } = node as unknown as { callee?: AstNode };
41
+ return identifierName(callee) === 'Set';
42
+ };
43
+
44
+ const isLocalReservedSetInitializer = (node: AstNode | undefined): boolean =>
45
+ node?.type === 'ArrayExpression' || isSetConstruction(node);
46
+
47
+ const buildDiagnostic = (
48
+ sourceCode: string,
49
+ filePath: string,
50
+ node: AstNode,
51
+ name: string
52
+ ): WardenDiagnostic => ({
53
+ filePath,
54
+ line: offsetToLine(sourceCode, node.start),
55
+ message: `layer-field-name-drift: surface-local reserved name set "${name}" can make layer input fields project differently across surfaces. Import LAYER_FIELD_RESERVED_NAMES from @ontrails/core instead.`,
56
+ rule: RULE_NAME,
57
+ severity: 'error',
58
+ });
59
+
60
+ export const layerFieldNameDrift: WardenRule = {
61
+ check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
62
+ if (!isSurfaceSourceFile(filePath) || isTestFile(filePath)) {
63
+ return [];
64
+ }
65
+
66
+ const ast = parse(filePath, sourceCode);
67
+ if (!ast) {
68
+ return [];
69
+ }
70
+
71
+ const diagnostics: WardenDiagnostic[] = [];
72
+ walk(ast, (node) => {
73
+ if (node.type !== 'VariableDeclarator') {
74
+ return;
75
+ }
76
+ const { id, init } = node as unknown as {
77
+ id?: AstNode;
78
+ init?: AstNode;
79
+ };
80
+ const name = identifierName(id);
81
+ if (
82
+ name &&
83
+ looksLikeLayerReservedNameSet(name) &&
84
+ isLocalReservedSetInitializer(init)
85
+ ) {
86
+ diagnostics.push(buildDiagnostic(sourceCode, filePath, node, name));
87
+ }
88
+ });
89
+
90
+ return diagnostics;
91
+ },
92
+ description:
93
+ 'Prevent surface-local reserved-name sets from drifting layer input field projection across surfaces.',
94
+ name: RULE_NAME,
95
+ severity: 'error',
96
+ };