@ontrails/warden 1.0.0-beta.39 → 1.0.0-beta.41

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 (134) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +5 -5
  3. package/package.json +10 -12
  4. package/src/cli.ts +49 -44
  5. package/src/command.ts +2 -2
  6. package/src/drift.ts +4 -3
  7. package/src/index.ts +3 -2
  8. package/src/project-context.ts +3 -3
  9. package/src/resolve.ts +2 -2
  10. package/src/rules/captured-kernel.ts +375 -0
  11. package/src/rules/circular-refs.ts +12 -16
  12. package/src/rules/cli-command-route-coherence.ts +1 -1
  13. package/src/rules/composes-declarations.ts +15 -13
  14. package/src/rules/context-no-surface-types.ts +4 -3
  15. package/src/rules/dead-internal-trail.ts +3 -3
  16. package/src/rules/dead-public-trail.ts +3 -3
  17. package/src/rules/draft-file-marking.ts +4 -9
  18. package/src/rules/draft-visible-debt.ts +3 -8
  19. package/src/rules/duplicate-public-contract.ts +50 -5
  20. package/src/rules/{contour-exists.ts → entity-exists.ts} +67 -64
  21. package/src/rules/entity-ids.ts +15 -0
  22. package/src/rules/error-mapping-completeness.ts +2 -2
  23. package/src/rules/example-valid.ts +84 -84
  24. package/src/rules/fires-declarations.ts +27 -22
  25. package/src/rules/governed-symbol-residue.ts +339 -32
  26. package/src/rules/implementation-returns-result.ts +8 -8
  27. package/src/rules/incomplete-accessor-for-standard-op.ts +15 -15
  28. package/src/rules/incomplete-crud.ts +42 -40
  29. package/src/rules/index.ts +9 -6
  30. package/src/rules/intent-propagation.ts +3 -5
  31. package/src/rules/layer-field-name-drift.ts +2 -2
  32. package/src/rules/library-projection-coherence.ts +2 -2
  33. package/src/rules/metadata.ts +37 -15
  34. package/src/rules/missing-reconcile.ts +3 -4
  35. package/src/rules/missing-visibility.ts +2 -1
  36. package/src/rules/no-destructured-compose.ts +14 -12
  37. package/src/rules/no-direct-implementation-call.ts +12 -7
  38. package/src/rules/no-legacy-cli-alias-export.ts +2 -2
  39. package/src/rules/no-native-error-result.ts +2 -2
  40. package/src/rules/no-redundant-result-error-wrap.ts +10 -10
  41. package/src/rules/no-sync-result-assumption.ts +84 -78
  42. package/src/rules/no-throw-in-detour-recover.ts +2 -2
  43. package/src/rules/no-throw-in-implementation.ts +13 -7
  44. package/src/rules/no-top-level-surface.ts +2 -2
  45. package/src/rules/on-references-exist.ts +3 -3
  46. package/src/rules/orphaned-signal.ts +4 -5
  47. package/src/rules/owner-projection-parity.ts +2 -2
  48. package/src/rules/public-export-example-coverage.ts +10 -4
  49. package/src/rules/public-internal-deep-imports.ts +2 -3
  50. package/src/rules/read-intent-fires.ts +4 -3
  51. package/src/rules/reference-exists.ts +20 -21
  52. package/src/rules/registry-names.ts +6 -4
  53. package/src/rules/resolved-import-boundary.ts +1 -1
  54. package/src/rules/resource-declarations.ts +21 -17
  55. package/src/rules/resource-exists.ts +4 -2
  56. package/src/rules/resource-id-grammar.ts +2 -2
  57. package/src/rules/resource-mock-coverage.ts +2 -2
  58. package/src/rules/retired-vocabulary.ts +242 -5
  59. package/src/rules/source/composition.ts +165 -0
  60. package/src/rules/source/drafts.ts +164 -0
  61. package/src/rules/source/entities.ts +618 -0
  62. package/src/rules/source/pragmas.ts +45 -0
  63. package/src/rules/source/resources.ts +64 -0
  64. package/src/rules/source/signals.ts +397 -0
  65. package/src/rules/source/stores.ts +310 -0
  66. package/src/rules/static-resource-accessor-preference.ts +15 -11
  67. package/src/rules/surface-overlay-coherence.ts +1 -1
  68. package/src/rules/surface-trailhead-coherence.ts +2 -2
  69. package/src/rules/trail-fork-coaching.ts +27 -18
  70. package/src/rules/trail-versioning-source.ts +16 -12
  71. package/src/rules/trail-versioning-topo.ts +2 -2
  72. package/src/rules/trailhead-override-divergence.ts +2 -2
  73. package/src/rules/types.ts +7 -7
  74. package/src/rules/unmaterialized-activation-source.ts +1 -0
  75. package/src/rules/unreachable-detour-shadowing.ts +2 -2
  76. package/src/rules/valid-describe-refs.ts +2 -2
  77. package/src/rules/warden-export-symmetry.ts +3 -3
  78. package/src/rules/warden-rules-use-ast.ts +12 -17
  79. package/src/trails/activation-orphan.trail.ts +5 -5
  80. package/src/trails/captured-kernel.trail.ts +108 -0
  81. package/src/trails/circular-refs.trail.ts +6 -6
  82. package/src/trails/cli-command-route-coherence.trail.ts +2 -2
  83. package/src/trails/composes-declarations.trail.ts +1 -1
  84. package/src/trails/context-no-surface-types.trail.ts +1 -1
  85. package/src/trails/dead-internal-trail.trail.ts +2 -2
  86. package/src/trails/dead-public-trail.trail.ts +1 -1
  87. package/src/trails/deprecation-without-guidance.trail.ts +1 -1
  88. package/src/trails/duplicate-public-contract.trail.ts +3 -3
  89. package/src/trails/entity-exists.trail.ts +21 -0
  90. package/src/trails/example-valid.trail.ts +3 -3
  91. package/src/trails/fires-declarations.trail.ts +1 -1
  92. package/src/trails/{fork-without-preserved-blaze.trail.ts → fork-without-preserved-implementation.trail.ts} +4 -4
  93. package/src/trails/implementation-returns-result.trail.ts +1 -1
  94. package/src/trails/incomplete-accessor-for-standard-op.trail.ts +4 -4
  95. package/src/trails/index.ts +3 -2
  96. package/src/trails/intent-propagation.trail.ts +2 -2
  97. package/src/trails/library-projection-coherence.trail.ts +2 -2
  98. package/src/trails/marker-schema-unsupported.trail.ts +1 -1
  99. package/src/trails/missing-visibility.trail.ts +1 -1
  100. package/src/trails/no-destructured-compose.trail.ts +5 -5
  101. package/src/trails/no-direct-implementation-call.trail.ts +1 -1
  102. package/src/trails/no-redundant-result-error-wrap.trail.ts +2 -2
  103. package/src/trails/no-sync-result-assumption.trail.ts +2 -2
  104. package/src/trails/no-throw-in-detour-recover.trail.ts +1 -1
  105. package/src/trails/no-throw-in-implementation.trail.ts +1 -1
  106. package/src/trails/on-references-exist.trail.ts +1 -1
  107. package/src/trails/pending-force.trail.ts +1 -1
  108. package/src/trails/permit-governance.trail.ts +2 -2
  109. package/src/trails/prefer-schema-inference.trail.ts +1 -1
  110. package/src/trails/public-output-schema.trail.ts +2 -2
  111. package/src/trails/public-union-output-discriminants.trail.ts +1 -1
  112. package/src/trails/read-intent-fires.trail.ts +1 -1
  113. package/src/trails/reference-exists.trail.ts +5 -5
  114. package/src/trails/resource-declarations.trail.ts +1 -1
  115. package/src/trails/resource-exists.trail.ts +1 -1
  116. package/src/trails/run.ts +4 -6
  117. package/src/trails/scheduled-destroy-intent.trail.ts +2 -2
  118. package/src/trails/schema.ts +9 -9
  119. package/src/trails/signal-graph-coaching.trail.ts +2 -2
  120. package/src/trails/static-resource-accessor-preference.trail.ts +1 -1
  121. package/src/trails/surface-overlay-coherence.trail.ts +1 -1
  122. package/src/trails/trail-fork-coaching.trail.ts +1 -1
  123. package/src/trails/unmaterialized-activation-source.trail.ts +5 -5
  124. package/src/trails/valid-detour-contract.trail.ts +1 -1
  125. package/src/trails/version-gap.trail.ts +1 -1
  126. package/src/trails/version-pinned-compose.trail.ts +1 -1
  127. package/src/trails/version-without-examples.trail.ts +1 -1
  128. package/src/trails/warden-rules-use-ast.trail.ts +2 -2
  129. package/src/trails/webhook-route-collision.trail.ts +2 -2
  130. package/src/trails/wrap-rule.ts +17 -17
  131. package/src/ast.ts +0 -137
  132. package/src/rules/ast.ts +0 -4143
  133. package/src/rules/contour-ids.ts +0 -15
  134. package/src/trails/contour-exists.trail.ts +0 -21
@@ -7,12 +7,12 @@ export const noSyncResultAssumptionTrail = wrapRule({
7
7
  expected: { diagnostics: [] },
8
8
  input: {
9
9
  filePath: 'clean.ts',
10
- sourceCode: `const result = await myTrail.blaze(input, ctx);
10
+ sourceCode: `const result = await myTrail.implementation(input, ctx);
11
11
  if (result.isOk()) {
12
12
  console.log(result.value);
13
13
  }`,
14
14
  },
15
- name: 'Properly awaited .blaze() call',
15
+ name: 'Properly awaited .implementation() call',
16
16
  },
17
17
  ],
18
18
  rule: noSyncResultAssumption,
@@ -14,7 +14,7 @@ export const noThrowInDetourRecoverTrail = wrapRule({
14
14
  recover: async () => Result.ok({ recovered: true }),
15
15
  },
16
16
  ],
17
- blaze: () => Result.err(new ConflictError("conflict")),
17
+ implementation: () => Result.err(new ConflictError("conflict")),
18
18
  })`,
19
19
  },
20
20
  name: 'Detour recover without throw',
@@ -8,7 +8,7 @@ export const noThrowInImplementationTrail = wrapRule({
8
8
  input: {
9
9
  filePath: 'clean.ts',
10
10
  sourceCode: `trail("entity.show", {
11
- blaze: async (input, ctx) => {
11
+ implementation: async (input, ctx) => {
12
12
  return Result.ok({ name: "test" });
13
13
  }
14
14
  })`,
@@ -11,7 +11,7 @@ export const onReferencesExistTrail = wrapRule({
11
11
  knownTrailIds: ['notify'],
12
12
  sourceCode: `trail("notify", {
13
13
  on: ["entity.created"],
14
- blaze: async (input, ctx) => Result.ok({}),
14
+ implementation: async (input, ctx) => Result.ok({}),
15
15
  })`,
16
16
  },
17
17
  name: 'Resolved on: reference',
@@ -1,5 +1,5 @@
1
1
  import { topo } from '@ontrails/core';
2
- import { deriveTopoGraph } from '@ontrails/topographer';
2
+ import { deriveTopoGraph } from '@ontrails/topography';
3
3
 
4
4
  import { pendingForce } from '../rules/trail-versioning-topo.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
@@ -5,14 +5,14 @@ import { permitGovernance } from '../rules/permit-governance.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  const destroyWithoutPermit = trail('entity.delete', {
8
- blaze: () => Result.ok({ ok: true }),
8
+ implementation: () => Result.ok({ ok: true }),
9
9
  input: z.object({}),
10
10
  intent: 'destroy',
11
11
  output: z.object({ ok: z.boolean() }),
12
12
  });
13
13
 
14
14
  const scopedDestroy = trail('entity.delete', {
15
- blaze: () => Result.ok({ ok: true }),
15
+ implementation: () => Result.ok({ ok: true }),
16
16
  input: z.object({}),
17
17
  intent: 'destroy',
18
18
  output: z.object({ ok: z.boolean() }),
@@ -9,7 +9,7 @@ export const preferSchemaInferenceTrail = wrapRule({
9
9
  filePath: 'clean.ts',
10
10
  sourceCode: `trail("entity.show", {
11
11
  input: z.object({ name: z.string() }),
12
- blaze: async (input, ctx) => {
12
+ implementation: async (input, ctx) => {
13
13
  return Result.ok({ name: input.name });
14
14
  }
15
15
  })`,
@@ -5,7 +5,7 @@ import { publicOutputSchema } from '../rules/public-output-schema.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  const cleanTrail = trail('report.read', {
8
- blaze: () => Result.ok({ ok: true }),
8
+ implementation: () => Result.ok({ ok: true }),
9
9
  input: z.object({}),
10
10
  output: z.object({ ok: z.boolean() }),
11
11
  });
@@ -15,7 +15,7 @@ const cleanTopo = topo('public-output-schema-clean', {
15
15
  });
16
16
 
17
17
  const missingOutputTrail = trail('report.missing', {
18
- blaze: () => Result.ok({ ok: true }),
18
+ implementation: () => Result.ok({ ok: true }),
19
19
  input: z.object({}),
20
20
  });
21
21
 
@@ -10,7 +10,7 @@ const cleanOutput = z.discriminatedUnion('kind', [
10
10
  ]);
11
11
 
12
12
  const cleanTrail = trail('report.read', {
13
- blaze: () => Result.ok({ kind: 'message' as const, message: 'ok' }),
13
+ implementation: () => Result.ok({ kind: 'message' as const, message: 'ok' }),
14
14
  input: z.object({}),
15
15
  output: cleanOutput,
16
16
  });
@@ -10,7 +10,7 @@ export const readIntentFiresTrail = wrapRule({
10
10
  sourceCode: `const entityLoaded = signal('entity.loaded', { payload: z.object({}) });
11
11
  trail('entity.read', {
12
12
  intent: 'read',
13
- blaze: async () => Result.ok({}),
13
+ implementation: async () => Result.ok({}),
14
14
  });`,
15
15
  },
16
16
  name: 'Read trails without fires stay quiet',
@@ -6,19 +6,19 @@ export const referenceExistsTrail = wrapRule({
6
6
  {
7
7
  expected: { diagnostics: [] },
8
8
  input: {
9
- filePath: 'contours.ts',
10
- knownContourIds: ['gist', 'user'],
9
+ filePath: 'entities.ts',
10
+ knownEntityIds: ['gist', 'user'],
11
11
  knownTrailIds: [],
12
- sourceCode: `const user = contour("user", {
12
+ sourceCode: `const user = entity("user", {
13
13
  id: z.string().uuid(),
14
14
  }, { identity: "id" });
15
15
 
16
- const gist = contour("gist", {
16
+ const gist = entity("gist", {
17
17
  id: z.string().uuid(),
18
18
  ownerId: user.id(),
19
19
  }, { identity: "id" });`,
20
20
  },
21
- name: 'Contour references resolve to known project contours',
21
+ name: 'Entity references resolve to known project entities',
22
22
  },
23
23
  ],
24
24
  rule: referenceExists,
@@ -13,7 +13,7 @@ export const resourceDeclarationsTrail = wrapRule({
13
13
 
14
14
  trail("entity.show", {
15
15
  resources: [db],
16
- blaze: async (_input, ctx) => {
16
+ implementation: async (_input, ctx) => {
17
17
  return Result.ok(db.from(ctx));
18
18
  }
19
19
  })`,
@@ -15,7 +15,7 @@ export const resourceExistsTrail = wrapRule({
15
15
 
16
16
  trail("entity.show", {
17
17
  resources: [db],
18
- blaze: async (_input, ctx) => {
18
+ implementation: async (_input, ctx) => {
19
19
  return Result.ok(db.from(ctx));
20
20
  }
21
21
  })`,
package/src/trails/run.ts CHANGED
@@ -34,13 +34,11 @@ const appendDiagnostics = (
34
34
  type TrailIntentMap = Readonly<Record<string, Intent>>;
35
35
 
36
36
  interface ProjectRuleOptions {
37
- readonly contourReferencesByName?: Readonly<
38
- Record<string, readonly string[]>
39
- >;
37
+ readonly entityReferencesByName?: Readonly<Record<string, readonly string[]>>;
40
38
  readonly composeTargetTrailIds?: readonly string[];
41
39
  readonly crudTableIds?: readonly string[];
42
40
  readonly crudCoverageByEntity?: Readonly<Record<string, readonly string[]>>;
43
- readonly knownContourIds?: readonly string[];
41
+ readonly knownEntityIds?: readonly string[];
44
42
  readonly importResolutionsByFile?: Readonly<
45
43
  Record<string, readonly WardenImportResolution[]>
46
44
  >;
@@ -57,11 +55,11 @@ interface ProjectRuleOptions {
57
55
  }
58
56
 
59
57
  const PROJECT_OPTION_KEYS = [
60
- 'contourReferencesByName',
58
+ 'entityReferencesByName',
61
59
  'composeTargetTrailIds',
62
60
  'crudTableIds',
63
61
  'crudCoverageByEntity',
64
- 'knownContourIds',
62
+ 'knownEntityIds',
65
63
  'importResolutionsByFile',
66
64
  'documentedImportResolutionsByFile',
67
65
  'knownResourceIds',
@@ -5,7 +5,7 @@ import { scheduledDestroyIntent } from '../rules/scheduled-destroy-intent.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  export const scheduledDestroyTrail = trail('billing.purge-expired', {
8
- blaze: () => Result.ok({ ok: true }),
8
+ implementation: () => Result.ok({ ok: true }),
9
9
  input: z.object({}),
10
10
  intent: 'destroy',
11
11
  on: [
@@ -18,7 +18,7 @@ export const scheduledDestroyTrail = trail('billing.purge-expired', {
18
18
  });
19
19
 
20
20
  const scheduledWriteTrail = trail('billing.reconcile', {
21
- blaze: () => Result.ok({ ok: true }),
21
+ implementation: () => Result.ok({ ok: true }),
22
22
  input: z.object({}),
23
23
  on: [schedule('schedule.billing.reconcile', { cron: '0 * * * *' })],
24
24
  output: z.object({ ok: z.boolean() }),
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { intentValues } from '@ontrails/core';
9
9
  import type { Topo } from '@ontrails/core';
10
- import type { TopoGraph } from '@ontrails/topographer';
10
+ import type { TopoGraph } from '@ontrails/topography';
11
11
  import { z } from 'zod';
12
12
  import { wardenImportResolutionErrorKinds } from '../resolve.js';
13
13
  import { wardenFixClasses, wardenFixSafeties } from '../rules/metadata.js';
@@ -106,7 +106,7 @@ export const exportedSymbolDefinitionSchema = z.object({
106
106
  * Extended input for project-aware warden rule trails.
107
107
  *
108
108
  * Adds `knownTrailIds` so the caller can supply compose-file context and avoid
109
- * false positives for `@see` references or compose-file contour relationships.
109
+ * false positives for `@see` references or compose-file entity relationships.
110
110
  */
111
111
  export const authoredMcpSurfaceBindingSetSchema = z.object({
112
112
  appName: z.string().describe('App/topo label the bindings were authored for'),
@@ -131,10 +131,6 @@ export const projectAwareRuleInput = ruleInput.extend({
131
131
  .array(z.string())
132
132
  .optional()
133
133
  .describe('Trail IDs referenced by composes arrays across the project'),
134
- contourReferencesByName: z
135
- .record(z.string(), z.array(z.string()))
136
- .optional()
137
- .describe('Declared contour references keyed by source contour name'),
138
134
  crudCoverageByEntity: z
139
135
  .record(z.string(), z.array(z.string()))
140
136
  .optional()
@@ -149,6 +145,10 @@ export const projectAwareRuleInput = ruleInput.extend({
149
145
  .record(z.string(), z.array(importResolutionSchema))
150
146
  .optional()
151
147
  .describe('Resolved docs/specifier facts keyed by documentation file path'),
148
+ entityReferencesByName: z
149
+ .record(z.string(), z.array(z.string()))
150
+ .optional()
151
+ .describe('Declared entity references keyed by source entity name'),
152
152
  exportedSymbolDefinitionsByName: z
153
153
  .record(z.string(), z.array(exportedSymbolDefinitionSchema))
154
154
  .optional()
@@ -157,10 +157,10 @@ export const projectAwareRuleInput = ruleInput.extend({
157
157
  .record(z.string(), z.array(importResolutionSchema))
158
158
  .optional()
159
159
  .describe('Resolved import facts keyed by importer file path'),
160
- knownContourIds: z
160
+ knownEntityIds: z
161
161
  .array(z.string())
162
162
  .optional()
163
- .describe('Contour names known across the project'),
163
+ .describe('Entity names known across the project'),
164
164
  knownResourceIds: z
165
165
  .array(z.string())
166
166
  .optional()
@@ -219,7 +219,7 @@ export const topoAwareRuleInput = z.object({
219
219
  value !== null &&
220
220
  'trails' in value &&
221
221
  'resources' in value &&
222
- 'contours' in value &&
222
+ 'entities' in value &&
223
223
  'signals' in value,
224
224
  { message: 'Expected a resolved Topo instance' }
225
225
  )
@@ -13,11 +13,11 @@ const producedSignal = signal('invoice.created', {
13
13
  });
14
14
 
15
15
  const producerTrail = trail('invoice.create', {
16
- blaze: async (_input, ctx) => {
16
+ fires: [producedSignal],
17
+ implementation: async (_input, ctx) => {
17
18
  await ctx.fire?.(producedSignal, { invoiceId: 'inv_1' });
18
19
  return Result.ok({ invoiceId: 'inv_1' });
19
20
  },
20
- fires: [producedSignal],
21
21
  input: z.object({}),
22
22
  output: z.object({ invoiceId: z.string() }),
23
23
  });
@@ -13,7 +13,7 @@ export const staticResourceAccessorPreferenceTrail = wrapRule({
13
13
 
14
14
  trail("entity.show", {
15
15
  resources: [db],
16
- blaze: async (_input, ctx) => {
16
+ implementation: async (_input, ctx) => {
17
17
  return Result.ok(db.from(ctx));
18
18
  }
19
19
  })`,
@@ -5,7 +5,7 @@ import { surfaceOverlayCoherence } from '../rules/surface-overlay-coherence.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  const listTrail = trail('gear.list', {
8
- blaze: () => Result.ok([]),
8
+ implementation: () => Result.ok([]),
9
9
  input: z.object({}),
10
10
  output: z.array(z.string()),
11
11
  });
@@ -25,7 +25,7 @@ export const usersManage = trail("users.manage", {
25
25
  input: z.object({
26
26
  action: z.enum(["create", "delete"]),
27
27
  }),
28
- blaze: async (input) => {
28
+ implementation: async (input) => {
29
29
  switch (input.action) {
30
30
  case "create":
31
31
  return Result.ok({ created: true });
@@ -10,7 +10,7 @@ const invoicePaidWebhook = webhook('webhook.invoice.paid', {
10
10
  });
11
11
 
12
12
  const webhookConsumer = trail('invoice.audit-webhook', {
13
- blaze: () => Result.ok({ ok: true }),
13
+ implementation: () => Result.ok({ ok: true }),
14
14
  input: z.object({ invoiceId: z.string() }),
15
15
  on: [invoicePaidWebhook],
16
16
  output: z.object({ ok: z.boolean() }),
@@ -22,24 +22,24 @@ const invoiceCreated = signal('invoice.created', {
22
22
  });
23
23
 
24
24
  const signalProducer = trail('invoice.create', {
25
- blaze: async (_input, ctx) => {
25
+ fires: [invoiceCreated],
26
+ implementation: async (_input, ctx) => {
26
27
  await ctx.fire?.(invoiceCreated, { invoiceId: 'inv_1' });
27
28
  return Result.ok({ invoiceId: 'inv_1' });
28
29
  },
29
- fires: [invoiceCreated],
30
30
  input: z.object({}),
31
31
  output: z.object({ invoiceId: z.string() }),
32
32
  });
33
33
 
34
34
  const signalConsumer = trail('invoice.index', {
35
- blaze: () => Result.ok({ ok: true }),
35
+ implementation: () => Result.ok({ ok: true }),
36
36
  input: z.object({ invoiceId: z.string() }),
37
37
  on: [invoiceCreated],
38
38
  output: z.object({ ok: z.boolean() }),
39
39
  });
40
40
 
41
41
  const scheduleConsumer = trail('invoice.reconcile', {
42
- blaze: () => Result.ok({ ok: true }),
42
+ implementation: () => Result.ok({ ok: true }),
43
43
  input: z.object({}),
44
44
  on: [schedule('schedule.invoice.reconcile', { cron: '0 * * * *' })],
45
45
  output: z.object({ ok: z.boolean() }),
@@ -5,7 +5,6 @@ import { validDetourContract } from '../rules/valid-detour-contract.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  const validTrail = trail('entity.save', {
8
- blaze: () => Result.ok({ ok: true }),
9
8
  detours: [
10
9
  {
11
10
  on: ConflictError,
@@ -15,6 +14,7 @@ const validTrail = trail('entity.save', {
15
14
  },
16
15
  },
17
16
  ],
17
+ implementation: () => Result.ok({ ok: true }),
18
18
  input: z.object({}),
19
19
  output: z.object({ ok: z.boolean() }),
20
20
  });
@@ -5,7 +5,7 @@ import { versionGap } from '../rules/trail-versioning-topo.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  const versionedTrail = trail('version.gap.clean', {
8
- blaze: () => Result.ok({ ok: true }),
8
+ implementation: () => Result.ok({ ok: true }),
9
9
  input: z.object({}),
10
10
  output: z.object({ ok: z.boolean() }),
11
11
  version: 2,
@@ -9,7 +9,7 @@ export const versionPinnedComposeTrail = wrapRule({
9
9
  filePath: 'src/trails/current.ts',
10
10
  sourceCode: `
11
11
  trail('current.parent', {
12
- blaze: async (_input, ctx) => {
12
+ implementation: async (_input, ctx) => {
13
13
  await ctx.compose('current.child', {});
14
14
  return Result.ok({});
15
15
  },
@@ -5,7 +5,7 @@ import { versionWithoutExamples } from '../rules/trail-versioning-topo.js';
5
5
  import { wrapTopoRule } from './wrap-rule.js';
6
6
 
7
7
  const archivedWithoutExamples = trail('version.examples.archived', {
8
- blaze: () => Result.ok({ ok: true }),
8
+ implementation: () => Result.ok({ ok: true }),
9
9
  input: z.object({}),
10
10
  output: z.object({ ok: z.boolean() }),
11
11
  version: 2,
@@ -28,7 +28,7 @@ export const wardenRulesUseAstTrail = wrapRule({
28
28
  filePath: fakeRulePath,
29
29
  line: 1,
30
30
  message:
31
- 'warden-rules-use-ast: sourceCode.split(...) treats source text as a string. Warden rules must inspect the AST via packages/warden/src/rules/ast.ts helpers, not regex-scan raw source text. Use findStringLiterals, findTrailDefinitions, findConfigProperty, or a similar AST walker. Raw-text scanning produces false positives on string literals, template payloads, and docstrings — see TRL-335, ADR-0036.',
31
+ 'warden-rules-use-ast: sourceCode.split(...) treats source text as a string. Warden rules must inspect source code via @ontrails/source helpers, not regex-scan raw source text. Use findStringLiterals, findTrailDefinitions, findConfigProperty, or a similar AST walker. Raw-text scanning produces false positives on string literals, template payloads, and docstrings — see TRL-335, ADR-0036.',
32
32
  rule: 'warden-rules-use-ast',
33
33
  severity: 'error',
34
34
  },
@@ -47,7 +47,7 @@ export const wardenRulesUseAstTrail = wrapRule({
47
47
  filePath: fakeRulePath,
48
48
  line: 1,
49
49
  message:
50
- 'warden-rules-use-ast: raw AST node-field cast should use typed helpers from ./ast.js (callee -> getNodeCallee). Raw node-field casts drift from the curated @ontrails/warden/ast guard surface.',
50
+ 'warden-rules-use-ast: raw AST node-field cast should use typed helpers from the shared source helpers (callee -> getNodeCallee). Raw node-field casts drift from the shared source helper surface.',
51
51
  rule: 'warden-rules-use-ast',
52
52
  severity: 'warn',
53
53
  },
@@ -10,14 +10,14 @@ const paymentWebhook = webhook('webhook.payment.received', {
10
10
  });
11
11
 
12
12
  const paymentReceiver = trail('payment.receive', {
13
- blaze: () => Result.ok({ ok: true }),
13
+ implementation: () => Result.ok({ ok: true }),
14
14
  input: z.object({ paymentId: z.string() }),
15
15
  on: [paymentWebhook],
16
16
  output: z.object({ ok: z.boolean() }),
17
17
  });
18
18
 
19
19
  const directRoute = trail('webhooks.payment', {
20
- blaze: () => Result.ok({ ok: true }),
20
+ implementation: () => Result.ok({ ok: true }),
21
21
  input: z.object({}),
22
22
  output: z.object({ ok: z.boolean() }),
23
23
  });
@@ -54,10 +54,10 @@ const buildProjectContext = (input: ProjectAwareRuleInput): ProjectContext => ({
54
54
  ...(input.authoredMcpSurfaceBindingSets
55
55
  ? { authoredMcpSurfaceBindingSets: input.authoredMcpSurfaceBindingSets }
56
56
  : {}),
57
- ...(input.contourReferencesByName
57
+ ...(input.entityReferencesByName
58
58
  ? {
59
- contourReferencesByName: new Map(
60
- Object.entries(input.contourReferencesByName)
59
+ entityReferencesByName: new Map(
60
+ Object.entries(input.entityReferencesByName)
61
61
  ),
62
62
  }
63
63
  : {}),
@@ -74,8 +74,8 @@ const buildProjectContext = (input: ProjectAwareRuleInput): ProjectContext => ({
74
74
  ),
75
75
  }
76
76
  : {}),
77
- ...(input.knownContourIds
78
- ? { knownContourIds: new Set(input.knownContourIds) }
77
+ ...(input.knownEntityIds
78
+ ? { knownEntityIds: new Set(input.knownEntityIds) }
79
79
  : {}),
80
80
  ...(input.importResolutionsByFile
81
81
  ? {
@@ -145,7 +145,12 @@ export function wrapRule(
145
145
  if (isProjectAware) {
146
146
  const projectAwareRule = rule as ProjectAwareWardenRule;
147
147
  return trail(`warden.rule.${rule.name}`, {
148
- blaze: (input: ProjectAwareRuleInput) => {
148
+ description: rule.description,
149
+ examples: examples as Trail<
150
+ ProjectAwareRuleInput,
151
+ RuleOutput
152
+ >['examples'],
153
+ implementation: (input: ProjectAwareRuleInput) => {
149
154
  const diagnostics = projectAwareRule.checkWithContext(
150
155
  input.sourceCode,
151
156
  input.filePath,
@@ -153,11 +158,6 @@ export function wrapRule(
153
158
  );
154
159
  return Result.ok({ diagnostics: [...diagnostics] });
155
160
  },
156
- description: rule.description,
157
- examples: examples as Trail<
158
- ProjectAwareRuleInput,
159
- RuleOutput
160
- >['examples'],
161
161
  input: projectAwareRuleInput,
162
162
  intent: 'read',
163
163
  meta: buildRuleMeta(rule),
@@ -166,12 +166,12 @@ export function wrapRule(
166
166
  }
167
167
 
168
168
  return trail(`warden.rule.${rule.name}`, {
169
- blaze: (input: RuleInput) => {
169
+ description: rule.description,
170
+ examples: examples as Trail<RuleInput, RuleOutput>['examples'],
171
+ implementation: (input: RuleInput) => {
170
172
  const diagnostics = rule.check(input.sourceCode, input.filePath);
171
173
  return Result.ok({ diagnostics: [...diagnostics] });
172
174
  },
173
- description: rule.description,
174
- examples: examples as Trail<RuleInput, RuleOutput>['examples'],
175
175
  input: ruleInput,
176
176
  intent: 'read',
177
177
  meta: buildRuleMeta(rule),
@@ -198,7 +198,9 @@ export const wrapTopoRule = (
198
198
  ): Trail<TopoAwareRuleInput, RuleOutput> => {
199
199
  const { rule, examples } = options;
200
200
  return trail(`warden.rule.${rule.name}`, {
201
- blaze: async (input: TopoAwareRuleInput) => {
201
+ description: rule.description,
202
+ examples,
203
+ implementation: async (input: TopoAwareRuleInput) => {
202
204
  try {
203
205
  const diagnostics = await rule.checkTopo(input.topo, {
204
206
  graph: input.graph,
@@ -214,8 +216,6 @@ export const wrapTopoRule = (
214
216
  );
215
217
  }
216
218
  },
217
- description: rule.description,
218
- examples,
219
219
  input: topoAwareRuleInput,
220
220
  intent: 'read',
221
221
  meta: buildRuleMeta(rule),