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

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 (36) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/package.json +15 -10
  3. package/src/adapter-check.ts +1 -1
  4. package/src/cli.ts +81 -5
  5. package/src/index.ts +17 -4
  6. package/src/regrade-history.ts +599 -0
  7. package/src/rules/cli-command-route-coherence.ts +6 -6
  8. package/src/rules/draft-visible-debt.ts +1 -1
  9. package/src/rules/duplicate-exported-symbol.ts +4 -43
  10. package/src/rules/governed-symbol-residue.ts +146 -53
  11. package/src/rules/governed-vocabulary-permutation-watch.ts +76 -0
  12. package/src/rules/implementation-returns-result.ts +99 -9
  13. package/src/rules/index.ts +17 -6
  14. package/src/rules/layer-field-name-drift.ts +2 -2
  15. package/src/rules/{library-projection-coherence.ts → library-render-coherence.ts} +11 -14
  16. package/src/rules/metadata.ts +51 -14
  17. package/src/rules/no-redundant-result-error-wrap.ts +15 -17
  18. package/src/rules/no-retired-cross-vocabulary.ts +0 -1
  19. package/src/rules/{owner-projection-parity.ts → owner-render-parity.ts} +18 -18
  20. package/src/rules/public-internal-deep-imports.ts +1 -3
  21. package/src/rules/public-output-schema.ts +1 -1
  22. package/src/rules/registry-names.ts +6 -4
  23. package/src/rules/retired-vocabulary.ts +775 -41
  24. package/src/rules/surface-overlay-coherence.ts +1 -1
  25. package/src/rules/trail-versioning-source.ts +1 -1
  26. package/src/rules/trailhead-override-divergence.ts +4 -4
  27. package/src/rules/types.ts +51 -5
  28. package/src/trails/governed-vocabulary-permutation-watch.trail.ts +16 -0
  29. package/src/trails/index.ts +3 -2
  30. package/src/trails/layer-field-name-drift.trail.ts +1 -1
  31. package/src/trails/{library-projection-coherence.trail.ts → library-render-coherence.trail.ts} +6 -6
  32. package/src/trails/{owner-projection-parity.trail.ts → owner-render-parity.trail.ts} +4 -4
  33. package/src/trails/public-output-schema.trail.ts +1 -1
  34. package/src/trails/run.ts +44 -2
  35. package/src/trails/schema.ts +41 -0
  36. package/src/trails/wrap-rule.ts +44 -2
@@ -40,6 +40,17 @@ export const governedVocabularyScopeSchema = z.object({
40
40
  extensions: z.array(z.string().min(1)).optional(),
41
41
  ignoredDirectories: z.array(z.string().min(1)).optional(),
42
42
  include: z.array(z.string().min(1)).optional(),
43
+ policyClassified: z
44
+ .array(
45
+ z.object({
46
+ disposition: z.enum(['explicit-preserve', 'historical-by-policy']),
47
+ expectMatches: z.boolean().optional(),
48
+ paths: z.array(z.string().min(1)).min(1),
49
+ reason: z.string().min(1),
50
+ })
51
+ )
52
+ .optional(),
53
+ teachingSurfaces: z.array(z.string().min(1)).optional(),
43
54
  });
44
55
 
45
56
  export const governedVocabularySymbolRenameMatchModes = [
@@ -65,12 +76,42 @@ export const governedVocabularyLiteralRenameSchema = z.object({
65
76
  to: z.string().min(1),
66
77
  });
67
78
 
79
+ export const governedVocabularyFileRenameSchema = z.object({
80
+ from: z.string().min(1),
81
+ to: z.string().min(1),
82
+ });
83
+
84
+ export const governedVocabularyProvenancePolicySchema = z.discriminatedUnion(
85
+ 'mode',
86
+ [
87
+ z.object({ mode: z.literal('regrade-history') }),
88
+ z.object({
89
+ mode: z.literal('legacy'),
90
+ reason: z.string().min(1),
91
+ }),
92
+ ]
93
+ );
94
+
95
+ export const governedVocabularyHistoryProvenanceSchema = z
96
+ .object({
97
+ disposition: z.enum(['applied-clean', 'review-follow-up']),
98
+ kind: z.literal('governed-vocabulary'),
99
+ planContentHash: z.string().regex(/^[0-9a-f]{64}$/),
100
+ reviewPending: z.number().int().nonnegative(),
101
+ safeApplied: z.number().int().nonnegative(),
102
+ sourceHashAfter: z.string().regex(/^[0-9a-f]{64}$/),
103
+ sourceHashBefore: z.string().regex(/^[0-9a-f]{64}$/),
104
+ transitionId: z.string().min(1),
105
+ })
106
+ .strict();
107
+
68
108
  export const governedVocabularyTransitionSchema = z.object({
69
109
  codeIdentifiers: z.array(z.string().min(1)).default([]),
70
110
  docs: z.object({
71
111
  guidance: z.array(z.string().min(1)).default([]),
72
112
  summary: z.string().min(1),
73
113
  }),
114
+ fileRenames: z.array(governedVocabularyFileRenameSchema).default([]),
74
115
  from: z.string().min(1),
75
116
  id: z.string().min(1),
76
117
  intent: z.string().min(1),
@@ -78,6 +119,11 @@ export const governedVocabularyTransitionSchema = z.object({
78
119
  oldForms: z.array(z.string().min(1)).min(1),
79
120
  overrides: z.record(z.string().min(1), z.string().min(1)).default({}),
80
121
  preserve: z.array(governedVocabularyPreserveRuleSchema).default([]),
122
+ provenance: governedVocabularyProvenancePolicySchema.default({
123
+ mode: 'legacy',
124
+ reason:
125
+ 'Transition completed before committed Regrade history provenance became enforceable.',
126
+ }),
81
127
  reviewForms: z.array(z.string().min(1)).default([]),
82
128
  safeRewriteForms: z.record(z.string().min(1), z.string().min(1)).default({}),
83
129
  scope: governedVocabularyScopeSchema.optional(),
@@ -113,6 +159,18 @@ export const governedVocabularyRegistrySchema = z
113
159
  });
114
160
  }
115
161
  seenFrom.add(transition.from);
162
+
163
+ if (
164
+ transition.status === 'planned' &&
165
+ transition.provenance.mode !== 'regrade-history'
166
+ ) {
167
+ ctx.addIssue({
168
+ code: 'custom',
169
+ message:
170
+ 'Planned governed transitions must require committed Regrade history provenance.',
171
+ path: [index, 'provenance'],
172
+ });
173
+ }
116
174
  }
117
175
  });
118
176
 
@@ -134,6 +192,12 @@ export type GovernedVocabularyLiteralRename = z.output<
134
192
  export type GovernedVocabularyTransition = z.output<
135
193
  typeof governedVocabularyTransitionSchema
136
194
  >;
195
+ export type GovernedVocabularyHistoryProvenance = z.output<
196
+ typeof governedVocabularyHistoryProvenanceSchema
197
+ >;
198
+ export type GovernedVocabularyProvenancePolicy = z.output<
199
+ typeof governedVocabularyProvenancePolicySchema
200
+ >;
137
201
  export type GovernedVocabularyTransitionInput = z.input<
138
202
  typeof governedVocabularyTransitionSchema
139
203
  >;
@@ -147,75 +211,66 @@ const reviewFunctionParamDeclarations = {
147
211
  reviewDeclarationTypes: ['FunctionParam'],
148
212
  };
149
213
 
150
- const v1VocabularyHistoricalExcludes = [
214
+ const v1VocabularyHardExcludes = [
215
+ '.scratch/**',
216
+ '**/.scratch/**',
217
+ '**/.tmp-tests/**',
218
+ ];
219
+
220
+ const v1VocabularyHistoricalPaths = [
151
221
  '.agents/goals/**',
152
222
  '**/.agents/goals/**',
153
223
  '.agents/memory/**',
154
224
  '**/.agents/memory/**',
155
225
  '.agents/notes/**',
156
226
  '**/.agents/notes/**',
227
+ '.agents/plans/**',
228
+ '**/.agents/plans/**',
157
229
  '.claude/agent-memory/**',
158
230
  '**/.claude/agent-memory/**',
159
- '.agents/plans/archive/**',
160
- '**/.agents/plans/archive/**',
161
231
  '.changeset/**',
162
232
  '**/.changeset/**',
163
- '.scratch/**',
164
- '**/.scratch/**',
165
- '.trails/regrade/history/**',
166
- '**/.trails/regrade/history/**',
233
+ '.trails/regrade/*.json',
234
+ '**/.trails/regrade/*.json',
167
235
  '**/CHANGELOG.md',
168
- '**/.tmp-tests/**',
169
- ];
170
-
171
- const v1VocabularyHistoricalPreservePaths = [
172
- '.agents/plans/**',
173
- '**/.agents/plans/**',
174
236
  'docs/adr/0*.md',
175
237
  'docs/adr/decision-map.json',
176
- 'docs/migration/**',
238
+ 'docs/migration/*-to-adapter.md',
239
+ 'docs/migration/*-to-compose.md',
240
+ 'docs/migration/trailhead-to-surface.md',
177
241
  'docs/releases/beta*.md',
178
242
  'docs/releases/v1-vocabulary-reset.md',
179
243
  'docs/releases/v1-vocabulary-transition-workflow.md',
180
- 'scripts/vocab-cutover-*.ts',
181
- ];
182
-
183
- const v1VocabularySelfExcludes = [
184
244
  'packages/warden/src/__tests__/retired-vocabulary.test.ts',
185
245
  'packages/warden/src/rules/retired-vocabulary.ts',
186
246
  ];
187
247
 
188
248
  const unique = (values: readonly string[]): string[] => [...new Set(values)];
189
249
 
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
250
  const defineV1Transition = (
197
251
  input: GovernedVocabularyTransitionInput
198
252
  ): GovernedVocabularyTransition =>
199
253
  defineTransition({
200
254
  ...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
- ],
255
+ preserve: input.preserve ?? [],
212
256
  scope: {
213
257
  ...input.scope,
214
258
  exclude: unique([
215
- ...v1VocabularyHistoricalExcludes,
216
- ...v1VocabularySelfExcludes,
259
+ ...v1VocabularyHardExcludes,
217
260
  ...(input.scope?.exclude ?? []),
218
261
  ]),
262
+ policyClassified: [
263
+ {
264
+ disposition: 'historical-by-policy',
265
+ paths: v1VocabularyHistoricalPaths,
266
+ reason:
267
+ 'Preserve authored migration plans and historical decision/release evidence while keeping occurrences visible to the run ledger.',
268
+ },
269
+ ...(input.scope?.policyClassified ?? []),
270
+ ],
271
+ ...(input.scope?.teachingSurfaces === undefined
272
+ ? {}
273
+ : { teachingSurfaces: input.scope.teachingSurfaces }),
219
274
  },
220
275
  });
221
276
 
@@ -339,6 +394,184 @@ export const governedVocabularyTransitions =
339
394
  ],
340
395
  target: { kind: 'single', to: 'entity' },
341
396
  }),
397
+ defineV1Transition({
398
+ codeIdentifiers: [
399
+ '@ontrails/observe',
400
+ '@ontrails/observe/logtape',
401
+ '@ontrails/observe/pino',
402
+ 'packages/observe',
403
+ ],
404
+ docs: {
405
+ guidance: [
406
+ 'Treat the public package routes as exact code strings and module specifiers, not as general observability vocabulary.',
407
+ 'Rewrite the temporary Pino and LogTape subpaths only to their renamed temporary owner; their extraction to top-level adapters is a later transition.',
408
+ ],
409
+ summary:
410
+ 'The dependency-light observability owner moved from @ontrails/observe to @ontrails/observability.',
411
+ },
412
+ from: '@ontrails/observe',
413
+ id: 'v1-observe-observability',
414
+ intent:
415
+ 'Rename the dependency-light observability owner and its temporary adapter subpaths for v1.',
416
+ kind: 'vocabulary',
417
+ oldForms: [
418
+ '@ontrails/observe',
419
+ '@ontrails/observe/logtape',
420
+ '@ontrails/observe/pino',
421
+ 'packages/observe',
422
+ ],
423
+ reviewForms: [],
424
+ safeRewriteForms: {
425
+ '@ontrails/observe': '@ontrails/observability',
426
+ '@ontrails/observe/logtape': '@ontrails/observability/logtape',
427
+ '@ontrails/observe/pino': '@ontrails/observability/pino',
428
+ 'packages/observe': 'packages/observability',
429
+ },
430
+ status: 'complete',
431
+ stringLiteralRenames: [
432
+ {
433
+ from: '@ontrails/observe',
434
+ moduleSpecifier: { targetPackage: '@ontrails/observability' },
435
+ to: '@ontrails/observability',
436
+ },
437
+ {
438
+ from: '@ontrails/observe/logtape',
439
+ moduleSpecifier: { targetPackage: '@ontrails/observability' },
440
+ to: '@ontrails/observability/logtape',
441
+ },
442
+ {
443
+ from: '@ontrails/observe/pino',
444
+ moduleSpecifier: { targetPackage: '@ontrails/observability' },
445
+ to: '@ontrails/observability/pino',
446
+ },
447
+ { from: 'packages/observe', to: 'packages/observability' },
448
+ ],
449
+ target: { kind: 'single', to: '@ontrails/observability' },
450
+ }),
451
+ defineV1Transition({
452
+ codeIdentifiers: ['@ontrails/observability/logtape'],
453
+ docs: {
454
+ guidance: [
455
+ 'Move the temporary observability subpath to the extracted LogTape adapter package.',
456
+ 'Do not retain a compatibility subpath: the extracted package owns the real LogTape dependency boundary.',
457
+ ],
458
+ summary:
459
+ 'The temporary LogTape forwarding subpath was extracted into a real top-level adapter package.',
460
+ },
461
+ from: '@ontrails/observability/logtape',
462
+ id: 'v1-observability-logtape-extraction',
463
+ intent:
464
+ 'Replace the temporary LogTape forwarding subpath with the extracted @ontrails/logtape adapter.',
465
+ kind: 'vocabulary',
466
+ oldForms: ['@ontrails/observability/logtape'],
467
+ reviewForms: [],
468
+ safeRewriteForms: {
469
+ '@ontrails/observability/logtape': '@ontrails/logtape',
470
+ },
471
+ status: 'complete',
472
+ stringLiteralRenames: [
473
+ {
474
+ from: '@ontrails/observability/logtape',
475
+ moduleSpecifier: { targetPackage: '@ontrails/logtape' },
476
+ to: '@ontrails/logtape',
477
+ },
478
+ ],
479
+ target: { kind: 'single', to: '@ontrails/logtape' },
480
+ }),
481
+ defineV1Transition({
482
+ codeIdentifiers: ['@ontrails/observability/pino'],
483
+ docs: {
484
+ guidance: [
485
+ 'Move the temporary observability subpath to the extracted Pino adapter package.',
486
+ 'Do not retain a compatibility subpath: the extracted package owns the real Pino dependency boundary.',
487
+ ],
488
+ summary:
489
+ 'The temporary Pino forwarding subpath was extracted into a real top-level adapter package.',
490
+ },
491
+ from: '@ontrails/observability/pino',
492
+ id: 'v1-observability-pino-extraction',
493
+ intent:
494
+ 'Replace the temporary Pino forwarding subpath with the extracted @ontrails/pino adapter.',
495
+ kind: 'vocabulary',
496
+ oldForms: ['@ontrails/observability/pino'],
497
+ reviewForms: [],
498
+ safeRewriteForms: {
499
+ '@ontrails/observability/pino': '@ontrails/pino',
500
+ },
501
+ status: 'complete',
502
+ stringLiteralRenames: [
503
+ {
504
+ from: '@ontrails/observability/pino',
505
+ moduleSpecifier: { targetPackage: '@ontrails/pino' },
506
+ to: '@ontrails/pino',
507
+ },
508
+ ],
509
+ target: { kind: 'single', to: '@ontrails/pino' },
510
+ }),
511
+ defineV1Transition({
512
+ codeIdentifiers: ['@ontrails/tracing', 'packages/tracing'],
513
+ docs: {
514
+ guidance: [
515
+ 'Classify root imports by ownership: intrinsic trace contracts belong to @ontrails/core and developer-state APIs belong to @ontrails/observability/dev.',
516
+ 'Do not mechanically redirect the tracing root because it formerly combined more than one owner.',
517
+ ],
518
+ summary:
519
+ 'The former tracing root was folded into core and the observability developer-state subpath.',
520
+ },
521
+ from: '@ontrails/tracing',
522
+ id: 'v1-tracing-owner-fold',
523
+ intent:
524
+ 'Remove the multi-owner tracing package without inventing a false one-to-one package redirect.',
525
+ kind: 'vocabulary',
526
+ oldForms: ['@ontrails/tracing', 'packages/tracing'],
527
+ reviewForms: [],
528
+ safeRewriteForms: {},
529
+ status: 'complete',
530
+ target: {
531
+ guidance:
532
+ 'Root tracing imports require ownership classification; use @ontrails/core for intrinsic contracts and @ontrails/observability/dev for developer-state APIs.',
533
+ kind: 'classified',
534
+ options: [
535
+ {
536
+ to: '@ontrails/core',
537
+ when: 'The imported symbol is an intrinsic trace record, context, or sink registry contract.',
538
+ },
539
+ {
540
+ to: '@ontrails/observability/dev',
541
+ when: 'The imported symbol is developer-state storage, sampling, or tracing query/status tooling.',
542
+ },
543
+ ],
544
+ },
545
+ }),
546
+ defineV1Transition({
547
+ codeIdentifiers: ['@ontrails/tracing/otel'],
548
+ docs: {
549
+ guidance: [
550
+ 'Rewrite the exact OTel adapter subpath after the observability package declares its /otel export.',
551
+ ],
552
+ summary:
553
+ 'The supported OTel adapter moved to the observability package.',
554
+ },
555
+ from: '@ontrails/tracing/otel',
556
+ id: 'v1-tracing-otel-observability-otel',
557
+ intent:
558
+ 'Move the dependency-light OTel adapter from the removed tracing package to @ontrails/observability/otel.',
559
+ kind: 'vocabulary',
560
+ oldForms: ['@ontrails/tracing/otel'],
561
+ reviewForms: [],
562
+ safeRewriteForms: {
563
+ '@ontrails/tracing/otel': '@ontrails/observability/otel',
564
+ },
565
+ status: 'complete',
566
+ stringLiteralRenames: [
567
+ {
568
+ from: '@ontrails/tracing/otel',
569
+ moduleSpecifier: { targetPackage: '@ontrails/observability' },
570
+ to: '@ontrails/observability/otel',
571
+ },
572
+ ],
573
+ target: { kind: 'single', to: '@ontrails/observability/otel' },
574
+ }),
342
575
  defineV1Transition({
343
576
  codeIdentifiers: [
344
577
  '@ontrails/topographer',
@@ -556,7 +789,105 @@ export const governedVocabularyTransitions =
556
789
  target: { kind: 'single', to: '@ontrails/topography' },
557
790
  }),
558
791
  defineV1Transition({
559
- codeIdentifiers: [],
792
+ codeIdentifiers: [
793
+ 'ActivationSourceProjection',
794
+ 'AstFieldProjection',
795
+ 'DeriveTrailCliCommandProjectionOptions',
796
+ 'ErrorClassSurfaceProjection',
797
+ 'ErrorDiagnosticsProjection',
798
+ 'HTTP_METHOD_PROJECTION_PATH',
799
+ 'HttpInputProjection',
800
+ 'HttpLayerInputProjection',
801
+ 'LayerFieldProjection',
802
+ 'LayerFlagProjection',
803
+ 'LibraryInputProjection',
804
+ 'LibraryLayerFieldProjection',
805
+ 'LibraryLayerInputProjection',
806
+ 'LibraryProjection',
807
+ 'McpInputProjection',
808
+ 'McpLayerInputProjection',
809
+ 'NormalizedTopoProjection',
810
+ 'OutputSchemaProjection',
811
+ 'PROJECTION_BLOCKING_RULES',
812
+ 'ProjectionMap',
813
+ 'ProjectedLayerField',
814
+ 'ProjectedPermitRequirement',
815
+ 'RenamedLayerFieldProjection',
816
+ 'ShippedSurfaceProjection',
817
+ 'SurfaceErrorProjection',
818
+ 'SurfaceProjectionSource',
819
+ 'SurfaceTrailVersionProjection',
820
+ 'TopoGraphLibraryProjection',
821
+ 'TopoStoreSurfaceProjectionRecord',
822
+ 'TopoSurfaceProjectionRow',
823
+ 'TrailCliCommandProjection',
824
+ 'TrailCliProjection',
825
+ 'TrailCliProjectionInput',
826
+ 'TrailErrorTaxonomyProjection',
827
+ 'buildOutputSchemaProjection',
828
+ 'buildProjectionDiagnostic',
829
+ 'cliProjection',
830
+ 'cliProjectionSchema',
831
+ 'collectLibraryProjection',
832
+ 'projectActivationEdge',
833
+ 'projectActivationSource',
834
+ 'projectActivationSourceDeclaration',
835
+ 'projectActual',
836
+ 'projectAstFields',
837
+ 'projectErrorClassSurface',
838
+ 'projectErrorDiagnostics',
839
+ 'projectExample',
840
+ 'projectHttpInputSchema',
841
+ 'projectHttpLayerInput',
842
+ 'projectInputForSchema',
843
+ 'projectLayerFieldName',
844
+ 'projectLayerFlags',
845
+ 'projectLayerInputFields',
846
+ 'projectLibraryInput',
847
+ 'projectMcpInputSchema',
848
+ 'projectMcpLayerInput',
849
+ 'projectMcpOutputSchema',
850
+ 'projectPermitRequirement',
851
+ 'projectPublicSurfaceError',
852
+ 'projectSchema',
853
+ 'projectSignalAssertion',
854
+ 'projectSignalAssertions',
855
+ 'projectSignalExample',
856
+ 'projectSingleLayerFlags',
857
+ 'projectSurfaceError',
858
+ 'projectSurfaceMapTool',
859
+ 'projectTrailVersionEntry',
860
+ 'projectTrailVersions',
861
+ 'projectVersionDetours',
862
+ 'projectVersionRuntimeRefs',
863
+ 'SchemaProjector',
864
+ 'deriveShippedSurfaceProjectionInventory',
865
+ 'deriveTrailCliCommandProjection',
866
+ 'errorSurfaceProjectionSchema',
867
+ 'errorTaxonomyProjectionSchema',
868
+ 'expectProjectionCounts',
869
+ 'inputProjection',
870
+ 'isProjectionBlockingIssue',
871
+ 'isTrailCliProjection',
872
+ 'keepProjectionBlockingIssues',
873
+ 'layerProjection',
874
+ 'libraryProjectionCoherence',
875
+ 'libraryProjectionCoherenceTrail',
876
+ 'normalizeTopoProjection',
877
+ 'ownerProjectionParity',
878
+ 'ownerProjectionParityTrail',
879
+ 'projectionDb',
880
+ 'projectionKeys',
881
+ 'projectionSource',
882
+ 'seedLegacyProjectionStore',
883
+ 'simpleProjectionApp',
884
+ 'surfaceProjectionBaseOutput',
885
+ 'surfaceProjectionOutput',
886
+ 'taxonomyProjection',
887
+ 'topoGraphLibraryProjectionSchema',
888
+ 'trailCliProjectionFor',
889
+ 'withProjectionDb',
890
+ ],
560
891
  docs: {
561
892
  guidance: [
562
893
  'Use derive for contract-owned fact production.',
@@ -565,15 +896,413 @@ export const governedVocabularyTransitions =
565
896
  ],
566
897
  summary: 'Projection vocabulary splits by stage into derive or render.',
567
898
  },
899
+ fileRenames: [
900
+ {
901
+ from: 'docs/adr/drafts/20260608-release-provenance-as-lifecycle-projection.md',
902
+ to: 'docs/adr/drafts/20260608-release-provenance-as-lifecycle-derivation.md',
903
+ },
904
+ {
905
+ from: 'packages/cli/src/__tests__/layer-input-projection.test.ts',
906
+ to: 'packages/cli/src/__tests__/layer-input-rendering.test.ts',
907
+ },
908
+ {
909
+ from: 'packages/core/src/__tests__/activation-source-projection.test.ts',
910
+ to: 'packages/core/src/__tests__/activation-source-derivation.test.ts',
911
+ },
912
+ {
913
+ from: 'packages/core/src/__tests__/error-projection.test.ts',
914
+ to: 'packages/core/src/__tests__/error-rendering.test.ts',
915
+ },
916
+ {
917
+ from: 'packages/core/src/activation-source-projection.ts',
918
+ to: 'packages/core/src/activation-source-derivation.ts',
919
+ },
920
+ {
921
+ from: 'packages/core/src/error-projection.ts',
922
+ to: 'packages/core/src/error-rendering.ts',
923
+ },
924
+ {
925
+ from: 'packages/core/src/layer-projection.ts',
926
+ to: 'packages/core/src/layer-field-rendering.ts',
927
+ },
928
+ {
929
+ from: 'packages/http/src/__tests__/layer-input-projection.test.ts',
930
+ to: 'packages/http/src/__tests__/layer-input-rendering.test.ts',
931
+ },
932
+ {
933
+ from: 'packages/mcp/src/__tests__/layer-input-projection.test.ts',
934
+ to: 'packages/mcp/src/__tests__/layer-input-rendering.test.ts',
935
+ },
936
+ {
937
+ from: 'packages/topography/src/library-projection.ts',
938
+ to: 'packages/topography/src/library-derivation.ts',
939
+ },
940
+ {
941
+ from: 'packages/warden/src/__tests__/library-projection-coherence.test.ts',
942
+ to: 'packages/warden/src/__tests__/library-render-coherence.test.ts',
943
+ },
944
+ {
945
+ from: 'packages/warden/src/__tests__/owner-projection-parity.test.ts',
946
+ to: 'packages/warden/src/__tests__/owner-render-parity.test.ts',
947
+ },
948
+ {
949
+ from: 'packages/warden/src/rules/library-projection-coherence.ts',
950
+ to: 'packages/warden/src/rules/library-render-coherence.ts',
951
+ },
952
+ {
953
+ from: 'packages/warden/src/rules/owner-projection-parity.ts',
954
+ to: 'packages/warden/src/rules/owner-render-parity.ts',
955
+ },
956
+ {
957
+ from: 'packages/warden/src/trails/library-projection-coherence.trail.ts',
958
+ to: 'packages/warden/src/trails/library-render-coherence.trail.ts',
959
+ },
960
+ {
961
+ from: 'packages/warden/src/trails/owner-projection-parity.trail.ts',
962
+ to: 'packages/warden/src/trails/owner-render-parity.trail.ts',
963
+ },
964
+ ],
568
965
  from: 'projection',
569
966
  id: 'v1-projection-derive-render',
570
967
  intent:
571
968
  'Split projection vocabulary into derive/render by lifecycle stage for v1.',
572
969
  kind: 'vocabulary',
573
- oldForms: ['projection', 'projections', 'project', 'projected'],
574
- reviewForms: ['projection', 'projections', 'project', 'projected'],
970
+ oldForms: [
971
+ 'projection',
972
+ 'projections',
973
+ 'project',
974
+ 'projects',
975
+ 'Projects',
976
+ 'projecting',
977
+ 'Projecting',
978
+ 'projected',
979
+ 'Projected',
980
+ ],
981
+ preserve: [
982
+ {
983
+ pattern: "\\b[Pp]roject(?:[-/:]|['’]s\\b)",
984
+ reason:
985
+ 'Preserve compound project-domain nouns, permit scopes, paths, and possessives without suppressing the standalone retired verb.',
986
+ },
987
+ {
988
+ pattern:
989
+ '\\b[Pp]roject\\s+(?:root|directory|files?|paths?|state|scripts?|guidance|structure|name|marker|context|conventions?|vocabulary|rules?|findings?|operations?|key|source|config|metadata|policy|package|scope|entities|resources|diagnostics|history|update|control|instructions?|overview|documentation|boundary|helpers?|shape|dependencies|dependency|detection|substrate|truth|work|writing|management|settings?|skills?|issue|ids?)\\b',
990
+ reason:
991
+ 'Preserve project as an attributive noun before established repository and workspace concepts.',
992
+ },
993
+ {
994
+ pattern:
995
+ '\\b(?:A|An|The|This|That|a|an|the|this|that|each|entire|every|existing|new|current|same|target|nested|downstream|Trails|Linear|Node|UX|logical|adopting|generated|scaffolded|source-shaped|first-party|temp)\\s+project\\b',
996
+ reason:
997
+ 'Preserve project as an ordinary count noun selected by a determiner or domain adjective.',
998
+ },
999
+ {
1000
+ pattern:
1001
+ "\\b(?:Trails|Matt[’']s|Vite|ADR|adopting|application|consumer|customer|developer|framework|package|software|source|workspace|generated|scaffolded|new|existing|source-shaped|first-party|downstream|most|large|all|many|multiple|other|our|several|their|these|those|your)\\s+projects\\b",
1002
+ reason:
1003
+ 'Preserve projects as an ordinary plural repository or application noun selected by an established domain modifier.',
1004
+ },
1005
+ {
1006
+ pattern:
1007
+ '\\b(?:across|among|between|for|from|in|inside|of|outside|under|within|with|without)\\s+(?:the\\s+)?projects\\b',
1008
+ reason:
1009
+ 'Preserve projects as the object of a repository or application preposition.',
1010
+ },
1011
+ {
1012
+ pattern:
1013
+ '(?:[\'"`/.][Pp]rojects(?:[\'"`/]|\\b)|\\b[Pp]rojects\\b\\s*(?:=|[):;,]))',
1014
+ reason:
1015
+ 'Preserve exact projects domain literals, member accesses, route segments, and enum values.',
1016
+ },
1017
+ {
1018
+ pattern:
1019
+ '\\b(?:in|for|within|across|under|outside|inside|from|of|with|without|per|before|after)\\s+(?:the\\s+)?project\\b',
1020
+ reason:
1021
+ 'Preserve project as the object of a repository or workspace preposition.',
1022
+ },
1023
+ {
1024
+ pattern:
1025
+ '(?:[\'"`/]project(?:[\'"`/]|\\b)|\\bproject\\b\\s*(?:=|[);,]))',
1026
+ reason:
1027
+ 'Preserve exact project domain literals, example variables, route segments, and enum values.',
1028
+ },
1029
+ {
1030
+ pattern:
1031
+ '(?:\\bmemory:\\s*project\\b|\\bproject\\b(?=\\s+(?:from|health-check|show)\\b))',
1032
+ reason:
1033
+ 'Preserve project as an exact metadata value, import alias, or domain command segment.',
1034
+ },
1035
+ {
1036
+ pattern:
1037
+ '(?:\\bA Node project\\b|\\ba non-trivial UX project\\b|\\bproject\\s+`warden\\.)',
1038
+ reason:
1039
+ 'Preserve established multiword project nouns and project-scoped Warden configuration prose.',
1040
+ },
1041
+ ],
1042
+ provenance: { mode: 'regrade-history' },
1043
+ reviewForms: [
1044
+ 'projection',
1045
+ 'projections',
1046
+ 'project',
1047
+ 'projects',
1048
+ 'Projects',
1049
+ 'projecting',
1050
+ 'Projecting',
1051
+ 'projected',
1052
+ 'Projected',
1053
+ ],
575
1054
  safeRewriteForms: {},
576
- status: 'planned',
1055
+ scope: {
1056
+ policyClassified: [
1057
+ {
1058
+ disposition: 'explicit-preserve',
1059
+ expectMatches: true,
1060
+ paths: [
1061
+ 'apps/trails/src/__tests__/mcp.test.ts',
1062
+ 'apps/trails/src/__tests__/regrade.test.ts',
1063
+ 'packages/regrade/src/downstream/__tests__/**/*.test.ts',
1064
+ ],
1065
+ reason:
1066
+ 'Preserve exact old/new vocabulary fixtures that prove CLI, MCP, registry, and rewrite behavior without treating them as current teaching or API residue.',
1067
+ },
1068
+ {
1069
+ disposition: 'historical-by-policy',
1070
+ expectMatches: true,
1071
+ paths: ['docs/adr/0*.md'],
1072
+ reason:
1073
+ 'The Trails projection census records accepted ADR history that must remain visible during the v1 split.',
1074
+ },
1075
+ ],
1076
+ teachingSurfaces: ['docs/**'],
1077
+ },
1078
+ status: 'complete',
1079
+ stringLiteralRenames: [
1080
+ {
1081
+ from: 'library-projection-coherence',
1082
+ to: 'library-render-coherence',
1083
+ },
1084
+ { from: 'owner-projection-parity', to: 'owner-render-parity' },
1085
+ { from: 'surface-projects', to: 'surface-renders' },
1086
+ ],
1087
+ symbolRenames: [
1088
+ { from: 'ActivationSourceProjection', to: 'ActivationSourceFacts' },
1089
+ { from: 'AstFieldProjection', to: 'AstFieldView' },
1090
+ {
1091
+ from: 'DeriveTrailCliCommandProjectionOptions',
1092
+ to: 'DeriveTrailCliCommandOptions',
1093
+ },
1094
+ {
1095
+ from: 'ErrorClassSurfaceProjection',
1096
+ to: 'ErrorClassSurfaceRendering',
1097
+ },
1098
+ {
1099
+ from: 'ErrorDiagnosticsProjection',
1100
+ to: 'ErrorDiagnosticsRendering',
1101
+ },
1102
+ {
1103
+ from: 'HTTP_METHOD_PROJECTION_PATH',
1104
+ to: 'HTTP_METHOD_DERIVATION_PATH',
1105
+ },
1106
+ { from: 'HttpInputProjection', to: 'HttpInputRendering' },
1107
+ {
1108
+ from: 'HttpLayerInputProjection',
1109
+ to: 'HttpLayerInputRendering',
1110
+ },
1111
+ { from: 'LayerFieldProjection', to: 'LayerFieldRendering' },
1112
+ { from: 'LayerFlagProjection', to: 'LayerFlagRendering' },
1113
+ { from: 'LibraryInputProjection', to: 'LibraryInputRendering' },
1114
+ {
1115
+ from: 'LibraryLayerFieldProjection',
1116
+ to: 'LibraryLayerFieldRendering',
1117
+ },
1118
+ {
1119
+ from: 'LibraryLayerInputProjection',
1120
+ to: 'LibraryLayerInputRendering',
1121
+ },
1122
+ { from: 'LibraryProjection', to: 'LibraryRenderingPlan' },
1123
+ { from: 'McpInputProjection', to: 'McpInputRendering' },
1124
+ {
1125
+ from: 'McpLayerInputProjection',
1126
+ to: 'McpLayerInputRendering',
1127
+ },
1128
+ { from: 'NormalizedTopoProjection', to: 'NormalizedTopoFacts' },
1129
+ {
1130
+ from: 'OutputSchemaProjection',
1131
+ to: 'McpOutputSchemaRendering',
1132
+ },
1133
+ {
1134
+ from: 'PROJECTION_BLOCKING_RULES',
1135
+ to: 'DERIVATION_BLOCKING_RULES',
1136
+ },
1137
+ { from: 'ProjectionMap', to: 'IntentKeyMap' },
1138
+ { from: 'ProjectedLayerField', to: 'RenderedLayerField' },
1139
+ {
1140
+ from: 'ProjectedPermitRequirement',
1141
+ to: 'DerivedPermitRequirement',
1142
+ },
1143
+ {
1144
+ from: 'RenamedLayerFieldProjection',
1145
+ to: 'RenamedLayerFieldRendering',
1146
+ },
1147
+ { from: 'ShippedSurfaceProjection', to: 'ShippedSurfaceDerived' },
1148
+ { from: 'SurfaceErrorProjection', to: 'SurfaceErrorRendering' },
1149
+ { from: 'SurfaceProjectionSource', to: 'SurfaceDerivedSource' },
1150
+ {
1151
+ from: 'SurfaceTrailVersionProjection',
1152
+ to: 'SurfaceTrailVersionRendering',
1153
+ },
1154
+ {
1155
+ from: 'TopoGraphLibraryProjection',
1156
+ to: 'TopoGraphLibraryDerived',
1157
+ },
1158
+ {
1159
+ from: 'TopoStoreSurfaceProjectionRecord',
1160
+ to: 'TopoStoreSurfaceDerivedRecord',
1161
+ },
1162
+ {
1163
+ from: 'TopoSurfaceProjectionRow',
1164
+ to: 'TopoSurfaceDerivedRow',
1165
+ },
1166
+ {
1167
+ from: 'TrailCliCommandProjection',
1168
+ to: 'TrailCliCommandRendering',
1169
+ },
1170
+ { from: 'TrailCliProjection', to: 'TrailCliRendering' },
1171
+ {
1172
+ from: 'TrailCliProjectionInput',
1173
+ to: 'TrailCliRenderingInput',
1174
+ },
1175
+ {
1176
+ from: 'TrailErrorTaxonomyProjection',
1177
+ to: 'TrailErrorTaxonomyFacts',
1178
+ },
1179
+ {
1180
+ from: 'buildOutputSchemaProjection',
1181
+ to: 'buildMcpOutputSchemaRendering',
1182
+ },
1183
+ {
1184
+ from: 'buildProjectionDiagnostic',
1185
+ to: 'buildDerivationDiagnostic',
1186
+ },
1187
+ { from: 'cliProjection', to: 'cliRendering' },
1188
+ { from: 'cliProjectionSchema', to: 'cliDerivedSchema' },
1189
+ {
1190
+ from: 'collectLibraryProjection',
1191
+ to: 'deriveTopoGraphLibrary',
1192
+ },
1193
+ { from: 'projectActivationEdge', to: 'deriveActivationEdge' },
1194
+ { from: 'projectActivationSource', to: 'deriveActivationSource' },
1195
+ {
1196
+ from: 'projectActivationSourceDeclaration',
1197
+ to: 'deriveActivationSourceFacts',
1198
+ },
1199
+ { from: 'projectActual', to: 'deriveActualOutcome' },
1200
+ { from: 'projectAstFields', to: 'deriveAstFieldView' },
1201
+ {
1202
+ from: 'projectErrorClassSurface',
1203
+ to: 'renderErrorClassSurface',
1204
+ },
1205
+ { from: 'projectErrorDiagnostics', to: 'renderErrorDiagnostics' },
1206
+ { from: 'projectExample', to: 'deriveExample' },
1207
+ { from: 'projectHttpInputSchema', to: 'renderHttpInputSchema' },
1208
+ { from: 'projectHttpLayerInput', to: 'renderHttpLayerInput' },
1209
+ { from: 'projectInputForSchema', to: 'deriveInputForSchema' },
1210
+ { from: 'projectLayerFieldName', to: 'renderLayerFieldName' },
1211
+ { from: 'projectLayerFlags', to: 'renderLayerFlags' },
1212
+ { from: 'projectLayerInputFields', to: 'renderLayerInputFields' },
1213
+ { from: 'projectLibraryInput', to: 'renderLibraryInput' },
1214
+ { from: 'projectMcpInputSchema', to: 'renderMcpInputSchema' },
1215
+ { from: 'projectMcpLayerInput', to: 'renderMcpLayerInput' },
1216
+ { from: 'projectMcpOutputSchema', to: 'renderMcpOutputSchema' },
1217
+ { from: 'projectPermitRequirement', to: 'derivePermitRequirement' },
1218
+ {
1219
+ from: 'projectPublicSurfaceError',
1220
+ to: 'renderPublicSurfaceError',
1221
+ },
1222
+ { from: 'projectSchema', to: 'deriveSchema' },
1223
+ { from: 'projectSignalAssertion', to: 'deriveSignalAssertion' },
1224
+ { from: 'projectSignalAssertions', to: 'deriveSignalAssertions' },
1225
+ { from: 'projectSignalExample', to: 'deriveSignalExample' },
1226
+ { from: 'projectSingleLayerFlags', to: 'renderSingleLayerFlags' },
1227
+ { from: 'projectSurfaceError', to: 'renderSurfaceError' },
1228
+ { from: 'projectSurfaceMapTool', to: 'renderSurfaceMapTool' },
1229
+ { from: 'projectTrailVersionEntry', to: 'deriveTrailVersionEntry' },
1230
+ { from: 'projectTrailVersions', to: 'deriveTrailVersions' },
1231
+ { from: 'projectVersionDetours', to: 'deriveVersionDetours' },
1232
+ {
1233
+ from: 'projectVersionRuntimeRefs',
1234
+ to: 'deriveVersionRuntimeRefs',
1235
+ },
1236
+ { from: 'SchemaProjector', to: 'SchemaDeriver' },
1237
+ {
1238
+ from: 'deriveShippedSurfaceProjectionInventory',
1239
+ to: 'deriveShippedSurfaceInventory',
1240
+ },
1241
+ {
1242
+ from: 'deriveTrailCliCommandProjection',
1243
+ to: 'deriveTrailCliCommandRendering',
1244
+ },
1245
+ {
1246
+ from: 'errorSurfaceProjectionSchema',
1247
+ to: 'errorSurfaceDerivedSchema',
1248
+ },
1249
+ {
1250
+ from: 'errorTaxonomyProjectionSchema',
1251
+ to: 'errorTaxonomyDerivedSchema',
1252
+ },
1253
+ { from: 'expectProjectionCounts', to: 'expectDerivedRowCounts' },
1254
+ { from: 'inputProjection', to: 'inputRendering' },
1255
+ {
1256
+ from: 'isProjectionBlockingIssue',
1257
+ to: 'isDerivationBlockingIssue',
1258
+ },
1259
+ { from: 'isTrailCliProjection', to: 'isTrailCliRendering' },
1260
+ {
1261
+ from: 'keepProjectionBlockingIssues',
1262
+ to: 'keepDerivationBlockingIssues',
1263
+ },
1264
+ { from: 'layerProjection', to: 'layerRendering' },
1265
+ {
1266
+ from: 'libraryProjectionCoherence',
1267
+ to: 'libraryRenderCoherence',
1268
+ },
1269
+ {
1270
+ from: 'libraryProjectionCoherenceTrail',
1271
+ to: 'libraryRenderCoherenceTrail',
1272
+ },
1273
+ {
1274
+ from: 'normalizeTopoProjection',
1275
+ to: 'deriveNormalizedTopoRows',
1276
+ },
1277
+ { from: 'ownerProjectionParity', to: 'ownerRenderParity' },
1278
+ {
1279
+ from: 'ownerProjectionParityTrail',
1280
+ to: 'ownerRenderParityTrail',
1281
+ },
1282
+ { from: 'projectionDb', to: 'derivedDb' },
1283
+ { from: 'projectionKeys', to: 'derivedKeys' },
1284
+ { from: 'projectionSource', to: 'derivedSource' },
1285
+ {
1286
+ from: 'seedLegacyProjectionStore',
1287
+ to: 'seedLegacyDerivedStore',
1288
+ },
1289
+ { from: 'simpleProjectionApp', to: 'simpleDerivedRowsApp' },
1290
+ {
1291
+ from: 'surfaceProjectionBaseOutput',
1292
+ to: 'surfaceDerivedBaseOutput',
1293
+ },
1294
+ {
1295
+ from: 'surfaceProjectionOutput',
1296
+ to: 'surfaceDerivedOutput',
1297
+ },
1298
+ { from: 'taxonomyProjection', to: 'deriveTaxonomyFacts' },
1299
+ {
1300
+ from: 'topoGraphLibraryProjectionSchema',
1301
+ to: 'topoGraphLibraryDerivedSchema',
1302
+ },
1303
+ { from: 'trailCliProjectionFor', to: 'trailCliRenderingFor' },
1304
+ { from: 'withProjectionDb', to: 'withDerivedDb' },
1305
+ ],
577
1306
  target: {
578
1307
  guidance:
579
1308
  'No single replacement is safe. Classify by whether the occurrence produces contract facts or presents derived facts.',
@@ -625,6 +1354,11 @@ export const formatGovernedVocabularyTransitionGuide = (
625
1354
  `- ${transition.id}: ${transition.from} -> ${target}`,
626
1355
  ` - Status: ${transition.status}`,
627
1356
  ` - Intent: ${transition.intent}`,
1357
+ ` - Provenance: ${
1358
+ transition.provenance.mode === 'regrade-history'
1359
+ ? 'committed Regrade history required'
1360
+ : `legacy (${transition.provenance.reason})`
1361
+ }`,
628
1362
  ` - Safe rewrites: ${Object.keys(transition.safeRewriteForms).length}`,
629
1363
  ` - Review forms: ${transition.reviewForms.join(', ') || 'none'}`,
630
1364
  ];