@principled/cairn 1.0.0-beta

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 (313) hide show
  1. package/README.md +182 -0
  2. package/dist/analysis/analyzer.d.ts +13 -0
  3. package/dist/analysis/analyzer.d.ts.map +1 -0
  4. package/dist/analysis/analyzer.js +47 -0
  5. package/dist/analysis/analyzer.js.map +1 -0
  6. package/dist/analysis/embedding-provider.d.ts +12 -0
  7. package/dist/analysis/embedding-provider.d.ts.map +1 -0
  8. package/dist/analysis/embedding-provider.js +21 -0
  9. package/dist/analysis/embedding-provider.js.map +1 -0
  10. package/dist/analysis/index.d.ts +4 -0
  11. package/dist/analysis/index.d.ts.map +1 -0
  12. package/dist/analysis/index.js +4 -0
  13. package/dist/analysis/index.js.map +1 -0
  14. package/dist/analysis/stub-provider.d.ts +12 -0
  15. package/dist/analysis/stub-provider.d.ts.map +1 -0
  16. package/dist/analysis/stub-provider.js +30 -0
  17. package/dist/analysis/stub-provider.js.map +1 -0
  18. package/dist/catalog/catalog.d.ts +40 -0
  19. package/dist/catalog/catalog.d.ts.map +1 -0
  20. package/dist/catalog/catalog.js +118 -0
  21. package/dist/catalog/catalog.js.map +1 -0
  22. package/dist/catalog/category-merger.d.ts +25 -0
  23. package/dist/catalog/category-merger.d.ts.map +1 -0
  24. package/dist/catalog/category-merger.js +75 -0
  25. package/dist/catalog/category-merger.js.map +1 -0
  26. package/dist/catalog/index.d.ts +4 -0
  27. package/dist/catalog/index.d.ts.map +1 -0
  28. package/dist/catalog/index.js +4 -0
  29. package/dist/catalog/index.js.map +1 -0
  30. package/dist/catalog/post-merge-validation.d.ts +7 -0
  31. package/dist/catalog/post-merge-validation.d.ts.map +1 -0
  32. package/dist/catalog/post-merge-validation.js +59 -0
  33. package/dist/catalog/post-merge-validation.js.map +1 -0
  34. package/dist/cli/commands/add.d.ts +3 -0
  35. package/dist/cli/commands/add.d.ts.map +1 -0
  36. package/dist/cli/commands/add.js +107 -0
  37. package/dist/cli/commands/add.js.map +1 -0
  38. package/dist/cli/commands/analyze.d.ts +3 -0
  39. package/dist/cli/commands/analyze.d.ts.map +1 -0
  40. package/dist/cli/commands/analyze.js +44 -0
  41. package/dist/cli/commands/analyze.js.map +1 -0
  42. package/dist/cli/commands/diff.d.ts +3 -0
  43. package/dist/cli/commands/diff.d.ts.map +1 -0
  44. package/dist/cli/commands/diff.js +69 -0
  45. package/dist/cli/commands/diff.js.map +1 -0
  46. package/dist/cli/commands/edit.d.ts +3 -0
  47. package/dist/cli/commands/edit.d.ts.map +1 -0
  48. package/dist/cli/commands/edit.js +93 -0
  49. package/dist/cli/commands/edit.js.map +1 -0
  50. package/dist/cli/commands/export.d.ts +3 -0
  51. package/dist/cli/commands/export.d.ts.map +1 -0
  52. package/dist/cli/commands/export.js +46 -0
  53. package/dist/cli/commands/export.js.map +1 -0
  54. package/dist/cli/commands/init.d.ts +3 -0
  55. package/dist/cli/commands/init.d.ts.map +1 -0
  56. package/dist/cli/commands/init.js +21 -0
  57. package/dist/cli/commands/init.js.map +1 -0
  58. package/dist/cli/commands/inspect.d.ts +3 -0
  59. package/dist/cli/commands/inspect.d.ts.map +1 -0
  60. package/dist/cli/commands/inspect.js +153 -0
  61. package/dist/cli/commands/inspect.js.map +1 -0
  62. package/dist/cli/commands/query.d.ts +3 -0
  63. package/dist/cli/commands/query.d.ts.map +1 -0
  64. package/dist/cli/commands/query.js +77 -0
  65. package/dist/cli/commands/query.js.map +1 -0
  66. package/dist/cli/commands/review.d.ts +3 -0
  67. package/dist/cli/commands/review.d.ts.map +1 -0
  68. package/dist/cli/commands/review.js +118 -0
  69. package/dist/cli/commands/review.js.map +1 -0
  70. package/dist/cli/commands/validate.d.ts +3 -0
  71. package/dist/cli/commands/validate.d.ts.map +1 -0
  72. package/dist/cli/commands/validate.js +125 -0
  73. package/dist/cli/commands/validate.js.map +1 -0
  74. package/dist/cli/helpers.d.ts +24 -0
  75. package/dist/cli/helpers.d.ts.map +1 -0
  76. package/dist/cli/helpers.js +152 -0
  77. package/dist/cli/helpers.js.map +1 -0
  78. package/dist/cli/index.d.ts +3 -0
  79. package/dist/cli/index.d.ts.map +1 -0
  80. package/dist/cli/index.js +34 -0
  81. package/dist/cli/index.js.map +1 -0
  82. package/dist/config/index.d.ts +5 -0
  83. package/dist/config/index.d.ts.map +1 -0
  84. package/dist/config/index.js +3 -0
  85. package/dist/config/index.js.map +1 -0
  86. package/dist/config/loader.d.ts +45 -0
  87. package/dist/config/loader.d.ts.map +1 -0
  88. package/dist/config/loader.js +201 -0
  89. package/dist/config/loader.js.map +1 -0
  90. package/dist/config/schema.d.ts +37 -0
  91. package/dist/config/schema.d.ts.map +1 -0
  92. package/dist/config/schema.js +42 -0
  93. package/dist/config/schema.js.map +1 -0
  94. package/dist/data/data/defaults.yaml +101 -0
  95. package/dist/data/defaults.yaml +101 -0
  96. package/dist/errors.d.ts +45 -0
  97. package/dist/errors.d.ts.map +1 -0
  98. package/dist/errors.js +84 -0
  99. package/dist/errors.js.map +1 -0
  100. package/dist/exporters/base.d.ts +17 -0
  101. package/dist/exporters/base.d.ts.map +1 -0
  102. package/dist/exporters/base.js +7 -0
  103. package/dist/exporters/base.js.map +1 -0
  104. package/dist/exporters/csv-exporter.d.ts +13 -0
  105. package/dist/exporters/csv-exporter.d.ts.map +1 -0
  106. package/dist/exporters/csv-exporter.js +73 -0
  107. package/dist/exporters/csv-exporter.js.map +1 -0
  108. package/dist/exporters/dot-exporter.d.ts +12 -0
  109. package/dist/exporters/dot-exporter.d.ts.map +1 -0
  110. package/dist/exporters/dot-exporter.js +72 -0
  111. package/dist/exporters/dot-exporter.js.map +1 -0
  112. package/dist/exporters/index.d.ts +8 -0
  113. package/dist/exporters/index.d.ts.map +1 -0
  114. package/dist/exporters/index.js +8 -0
  115. package/dist/exporters/index.js.map +1 -0
  116. package/dist/exporters/json-exporter.d.ts +14 -0
  117. package/dist/exporters/json-exporter.d.ts.map +1 -0
  118. package/dist/exporters/json-exporter.js +41 -0
  119. package/dist/exporters/json-exporter.js.map +1 -0
  120. package/dist/exporters/markdown-exporter.d.ts +14 -0
  121. package/dist/exporters/markdown-exporter.d.ts.map +1 -0
  122. package/dist/exporters/markdown-exporter.js +65 -0
  123. package/dist/exporters/markdown-exporter.js.map +1 -0
  124. package/dist/exporters/registry.d.ts +4 -0
  125. package/dist/exporters/registry.d.ts.map +1 -0
  126. package/dist/exporters/registry.js +20 -0
  127. package/dist/exporters/registry.js.map +1 -0
  128. package/dist/exporters/sqlite-exporter.d.ts +10 -0
  129. package/dist/exporters/sqlite-exporter.d.ts.map +1 -0
  130. package/dist/exporters/sqlite-exporter.js +20 -0
  131. package/dist/exporters/sqlite-exporter.js.map +1 -0
  132. package/dist/index.d.ts +13 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +14 -0
  135. package/dist/index.js.map +1 -0
  136. package/dist/inheritance/alias-resolver.d.ts +21 -0
  137. package/dist/inheritance/alias-resolver.d.ts.map +1 -0
  138. package/dist/inheritance/alias-resolver.js +40 -0
  139. package/dist/inheritance/alias-resolver.js.map +1 -0
  140. package/dist/inheritance/index.d.ts +9 -0
  141. package/dist/inheritance/index.d.ts.map +1 -0
  142. package/dist/inheritance/index.js +5 -0
  143. package/dist/inheritance/index.js.map +1 -0
  144. package/dist/inheritance/inheritance-resolver.d.ts +37 -0
  145. package/dist/inheritance/inheritance-resolver.d.ts.map +1 -0
  146. package/dist/inheritance/inheritance-resolver.js +164 -0
  147. package/dist/inheritance/inheritance-resolver.js.map +1 -0
  148. package/dist/inheritance/reference-parser.d.ts +27 -0
  149. package/dist/inheritance/reference-parser.d.ts.map +1 -0
  150. package/dist/inheritance/reference-parser.js +74 -0
  151. package/dist/inheritance/reference-parser.js.map +1 -0
  152. package/dist/inheritance/source-resolver.d.ts +29 -0
  153. package/dist/inheritance/source-resolver.d.ts.map +1 -0
  154. package/dist/inheritance/source-resolver.js +87 -0
  155. package/dist/inheritance/source-resolver.js.map +1 -0
  156. package/dist/model/category-registry.d.ts +48 -0
  157. package/dist/model/category-registry.d.ts.map +1 -0
  158. package/dist/model/category-registry.js +83 -0
  159. package/dist/model/category-registry.js.map +1 -0
  160. package/dist/model/document-meta.d.ts +38 -0
  161. package/dist/model/document-meta.d.ts.map +1 -0
  162. package/dist/model/document-meta.js +62 -0
  163. package/dist/model/document-meta.js.map +1 -0
  164. package/dist/model/document-parser.d.ts +17 -0
  165. package/dist/model/document-parser.d.ts.map +1 -0
  166. package/dist/model/document-parser.js +66 -0
  167. package/dist/model/document-parser.js.map +1 -0
  168. package/dist/model/document.d.ts +27 -0
  169. package/dist/model/document.d.ts.map +1 -0
  170. package/dist/model/document.js +42 -0
  171. package/dist/model/document.js.map +1 -0
  172. package/dist/model/element.d.ts +51 -0
  173. package/dist/model/element.d.ts.map +1 -0
  174. package/dist/model/element.js +78 -0
  175. package/dist/model/element.js.map +1 -0
  176. package/dist/model/graph.d.ts +42 -0
  177. package/dist/model/graph.d.ts.map +1 -0
  178. package/dist/model/graph.js +177 -0
  179. package/dist/model/graph.js.map +1 -0
  180. package/dist/model/index.d.ts +8 -0
  181. package/dist/model/index.d.ts.map +1 -0
  182. package/dist/model/index.js +7 -0
  183. package/dist/model/index.js.map +1 -0
  184. package/dist/parsers/base.d.ts +28 -0
  185. package/dist/parsers/base.d.ts.map +1 -0
  186. package/dist/parsers/base.js +19 -0
  187. package/dist/parsers/base.js.map +1 -0
  188. package/dist/parsers/index.d.ts +6 -0
  189. package/dist/parsers/index.d.ts.map +1 -0
  190. package/dist/parsers/index.js +6 -0
  191. package/dist/parsers/index.js.map +1 -0
  192. package/dist/parsers/markdown-parser.d.ts +12 -0
  193. package/dist/parsers/markdown-parser.d.ts.map +1 -0
  194. package/dist/parsers/markdown-parser.js +37 -0
  195. package/dist/parsers/markdown-parser.js.map +1 -0
  196. package/dist/parsers/registry.d.ts +11 -0
  197. package/dist/parsers/registry.d.ts.map +1 -0
  198. package/dist/parsers/registry.js +21 -0
  199. package/dist/parsers/registry.js.map +1 -0
  200. package/dist/parsers/typescript-parser.d.ts +12 -0
  201. package/dist/parsers/typescript-parser.d.ts.map +1 -0
  202. package/dist/parsers/typescript-parser.js +74 -0
  203. package/dist/parsers/typescript-parser.js.map +1 -0
  204. package/dist/parsers/yaml-parser.d.ts +12 -0
  205. package/dist/parsers/yaml-parser.d.ts.map +1 -0
  206. package/dist/parsers/yaml-parser.js +30 -0
  207. package/dist/parsers/yaml-parser.js.map +1 -0
  208. package/dist/provenance/index.d.ts +5 -0
  209. package/dist/provenance/index.d.ts.map +1 -0
  210. package/dist/provenance/index.js +4 -0
  211. package/dist/provenance/index.js.map +1 -0
  212. package/dist/provenance/review-hash.d.ts +11 -0
  213. package/dist/provenance/review-hash.d.ts.map +1 -0
  214. package/dist/provenance/review-hash.js +18 -0
  215. package/dist/provenance/review-hash.js.map +1 -0
  216. package/dist/provenance/schemas.d.ts +36 -0
  217. package/dist/provenance/schemas.d.ts.map +1 -0
  218. package/dist/provenance/schemas.js +26 -0
  219. package/dist/provenance/schemas.js.map +1 -0
  220. package/dist/provenance/staleness.d.ts +12 -0
  221. package/dist/provenance/staleness.d.ts.map +1 -0
  222. package/dist/provenance/staleness.js +46 -0
  223. package/dist/provenance/staleness.js.map +1 -0
  224. package/dist/refs/git-diff-tracer.d.ts +35 -0
  225. package/dist/refs/git-diff-tracer.d.ts.map +1 -0
  226. package/dist/refs/git-diff-tracer.js +143 -0
  227. package/dist/refs/git-diff-tracer.js.map +1 -0
  228. package/dist/schema/build-schema.d.ts +15 -0
  229. package/dist/schema/build-schema.d.ts.map +1 -0
  230. package/dist/schema/build-schema.js +83 -0
  231. package/dist/schema/build-schema.js.map +1 -0
  232. package/dist/schema/category-definition.d.ts +41 -0
  233. package/dist/schema/category-definition.d.ts.map +1 -0
  234. package/dist/schema/category-definition.js +22 -0
  235. package/dist/schema/category-definition.js.map +1 -0
  236. package/dist/schema/combined-schema.d.ts +17 -0
  237. package/dist/schema/combined-schema.d.ts.map +1 -0
  238. package/dist/schema/combined-schema.js +23 -0
  239. package/dist/schema/combined-schema.js.map +1 -0
  240. package/dist/schema/datetime.d.ts +11 -0
  241. package/dist/schema/datetime.d.ts.map +1 -0
  242. package/dist/schema/datetime.js +81 -0
  243. package/dist/schema/datetime.js.map +1 -0
  244. package/dist/schema/defaults-loader.d.ts +21 -0
  245. package/dist/schema/defaults-loader.d.ts.map +1 -0
  246. package/dist/schema/defaults-loader.js +55 -0
  247. package/dist/schema/defaults-loader.js.map +1 -0
  248. package/dist/schema/field-schema.d.ts +23 -0
  249. package/dist/schema/field-schema.d.ts.map +1 -0
  250. package/dist/schema/field-schema.js +18 -0
  251. package/dist/schema/field-schema.js.map +1 -0
  252. package/dist/schema/index.d.ts +17 -0
  253. package/dist/schema/index.d.ts.map +1 -0
  254. package/dist/schema/index.js +17 -0
  255. package/dist/schema/index.js.map +1 -0
  256. package/dist/schema/reserved-fields.d.ts +32 -0
  257. package/dist/schema/reserved-fields.d.ts.map +1 -0
  258. package/dist/schema/reserved-fields.js +42 -0
  259. package/dist/schema/reserved-fields.js.map +1 -0
  260. package/dist/schema/types.d.ts +7 -0
  261. package/dist/schema/types.d.ts.map +1 -0
  262. package/dist/schema/types.js +9 -0
  263. package/dist/schema/types.js.map +1 -0
  264. package/dist/utils/logger.d.ts +7 -0
  265. package/dist/utils/logger.d.ts.map +1 -0
  266. package/dist/utils/logger.js +16 -0
  267. package/dist/utils/logger.js.map +1 -0
  268. package/dist/utils/project-root.d.ts +14 -0
  269. package/dist/utils/project-root.d.ts.map +1 -0
  270. package/dist/utils/project-root.js +48 -0
  271. package/dist/utils/project-root.js.map +1 -0
  272. package/dist/validation/diagnostic.d.ts +23 -0
  273. package/dist/validation/diagnostic.d.ts.map +1 -0
  274. package/dist/validation/diagnostic.js +5 -0
  275. package/dist/validation/diagnostic.js.map +1 -0
  276. package/dist/validation/index.d.ts +6 -0
  277. package/dist/validation/index.d.ts.map +1 -0
  278. package/dist/validation/index.js +4 -0
  279. package/dist/validation/index.js.map +1 -0
  280. package/dist/validation/passes/coverage-pass.d.ts +10 -0
  281. package/dist/validation/passes/coverage-pass.d.ts.map +1 -0
  282. package/dist/validation/passes/coverage-pass.js +99 -0
  283. package/dist/validation/passes/coverage-pass.js.map +1 -0
  284. package/dist/validation/passes/index.d.ts +6 -0
  285. package/dist/validation/passes/index.d.ts.map +1 -0
  286. package/dist/validation/passes/index.js +19 -0
  287. package/dist/validation/passes/index.js.map +1 -0
  288. package/dist/validation/passes/schema-pass.d.ts +12 -0
  289. package/dist/validation/passes/schema-pass.d.ts.map +1 -0
  290. package/dist/validation/passes/schema-pass.js +38 -0
  291. package/dist/validation/passes/schema-pass.js.map +1 -0
  292. package/dist/validation/passes/semantic-pass.d.ts +8 -0
  293. package/dist/validation/passes/semantic-pass.d.ts.map +1 -0
  294. package/dist/validation/passes/semantic-pass.js +126 -0
  295. package/dist/validation/passes/semantic-pass.js.map +1 -0
  296. package/dist/validation/passes/structural-pass.d.ts +8 -0
  297. package/dist/validation/passes/structural-pass.d.ts.map +1 -0
  298. package/dist/validation/passes/structural-pass.js +150 -0
  299. package/dist/validation/passes/structural-pass.js.map +1 -0
  300. package/dist/validation/passes/traceability-pass.d.ts +9 -0
  301. package/dist/validation/passes/traceability-pass.d.ts.map +1 -0
  302. package/dist/validation/passes/traceability-pass.js +87 -0
  303. package/dist/validation/passes/traceability-pass.js.map +1 -0
  304. package/dist/validation/passes/user-rules-pass.d.ts +9 -0
  305. package/dist/validation/passes/user-rules-pass.d.ts.map +1 -0
  306. package/dist/validation/passes/user-rules-pass.js +72 -0
  307. package/dist/validation/passes/user-rules-pass.js.map +1 -0
  308. package/dist/validation/runner.d.ts +17 -0
  309. package/dist/validation/runner.d.ts.map +1 -0
  310. package/dist/validation/runner.js +33 -0
  311. package/dist/validation/runner.js.map +1 -0
  312. package/package.json +43 -0
  313. package/src/data/defaults.yaml +101 -0
@@ -0,0 +1,99 @@
1
+ import { createDiagnostic } from '../diagnostic.js';
2
+ import { createRefParserRegistry } from '../../parsers/registry.js';
3
+ import { findProjectRoot } from '../../utils/project-root.js';
4
+ import { minimatch } from 'minimatch';
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ const PASS_NAME = 'coverage';
8
+ const EXCLUDE_PATTERNS = [
9
+ /node_modules/,
10
+ /\/dist\//,
11
+ /\.test\.[jt]sx?$/,
12
+ /\.spec\.[jt]sx?$/,
13
+ /__tests__\//,
14
+ ];
15
+ /**
16
+ * Coverage pass — bidirectional ref coverage check (W012, W013).
17
+ * This is an optional pass, not part of the 5 canonical passes.
18
+ * Only runs when explicitly requested.
19
+ */
20
+ export function coveragePass(catalog, config) {
21
+ const diagnostics = [];
22
+ const parsers = createRefParserRegistry();
23
+ // Build set of all referenced file::identifier pairs
24
+ const referencedPairs = new Set();
25
+ for (const element of catalog.getAllElements()) {
26
+ const refs = element.get('refs');
27
+ if (!refs)
28
+ continue;
29
+ for (const ref of refs) {
30
+ referencedPairs.add(`${ref.file}::${ref.identifier}`);
31
+ }
32
+ }
33
+ // W012: Orphan identifiers — parser-driven discovery
34
+ const excludePatterns = config.coverage?.exclude ?? [];
35
+ const projectRoot = findProjectRoot(catalog);
36
+ if (projectRoot) {
37
+ for (const parser of parsers) {
38
+ const files = collectFilesByExtension(projectRoot, parser.extensions);
39
+ for (const absFile of files) {
40
+ const relFile = path.relative(projectRoot, absFile);
41
+ if (EXCLUDE_PATTERNS.some(p => p.test(relFile)))
42
+ continue;
43
+ if (excludePatterns.some(pattern => minimatch(relFile, pattern, { dot: true })))
44
+ continue;
45
+ try {
46
+ const content = fs.readFileSync(absFile, 'utf-8');
47
+ const identifiers = parser.extractIdentifiers(content);
48
+ for (const { identifier } of identifiers) {
49
+ const key = `${relFile}::${identifier}`;
50
+ if (!referencedPairs.has(key)) {
51
+ diagnostics.push(createDiagnostic('W012', 'ORPHAN_IDENTIFIER', `Identifier '${identifier}' in ${relFile} is not referenced by any GVP element`, 'warning', PASS_NAME, { details: key }));
52
+ }
53
+ }
54
+ }
55
+ catch {
56
+ // File read error — skip
57
+ }
58
+ }
59
+ }
60
+ }
61
+ // W013: Decision has no refs (scoped to decisions only)
62
+ for (const element of catalog.getAllElements()) {
63
+ if (element.status !== 'active')
64
+ continue;
65
+ if (element.categoryName !== 'decision')
66
+ continue;
67
+ const refs = element.get('refs');
68
+ if (!refs || !Array.isArray(refs) || refs.length === 0) {
69
+ diagnostics.push(createDiagnostic('W013', 'DECISION_NO_REFS', `Decision ${element.toLibraryId()} has no refs`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, categoryName: element.categoryName }));
70
+ }
71
+ }
72
+ return diagnostics;
73
+ }
74
+ /**
75
+ * Recursively collect files matching given extensions, excluding test/dist/node_modules.
76
+ */
77
+ function collectFilesByExtension(dir, extensions) {
78
+ const files = [];
79
+ try {
80
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
81
+ for (const entry of entries) {
82
+ const fullPath = path.join(dir, entry.name);
83
+ if (EXCLUDE_PATTERNS.some(p => p.test(fullPath)))
84
+ continue;
85
+ if (entry.isDirectory()) {
86
+ files.push(...collectFilesByExtension(fullPath, extensions));
87
+ }
88
+ else if (entry.isFile()) {
89
+ const ext = path.extname(entry.name).toLowerCase();
90
+ if (extensions.includes(ext)) {
91
+ files.push(fullPath);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ catch { /* skip unreadable dirs */ }
97
+ return files;
98
+ }
99
+ //# sourceMappingURL=coverage-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage-pass.js","sourceRoot":"","sources":["../../../src/validation/passes/coverage-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ValidationPass } from '../runner.js';
2
+ /** Built-in validation passes in canonical order (DEC-5.9) */
3
+ export declare const builtinPasses: Map<string, ValidationPass>;
4
+ /** Optional passes that only run when explicitly requested */
5
+ export declare const optionalPasses: Map<string, ValidationPass>;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/validation/passes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAQnD,8DAA8D;AAC9D,eAAO,MAAM,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAMpD,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAErD,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { schemaPass } from './schema-pass.js';
2
+ import { structuralPass } from './structural-pass.js';
3
+ import { traceabilityPass } from './traceability-pass.js';
4
+ import { semanticPass } from './semantic-pass.js';
5
+ import { userRulesPass } from './user-rules-pass.js';
6
+ import { coveragePass } from './coverage-pass.js';
7
+ /** Built-in validation passes in canonical order (DEC-5.9) */
8
+ export const builtinPasses = new Map([
9
+ ['schema', schemaPass],
10
+ ['structural', structuralPass],
11
+ ['traceability', traceabilityPass],
12
+ ['semantic', semanticPass],
13
+ ['user_rules', userRulesPass],
14
+ ]);
15
+ /** Optional passes that only run when explicitly requested */
16
+ export const optionalPasses = new Map([
17
+ ['coverage', coveragePass],
18
+ ]);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/validation/passes/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAgC,IAAI,GAAG,CAAC;IAChE,CAAC,QAAQ,EAAE,UAAU,CAAC;IACtB,CAAC,YAAY,EAAE,cAAc,CAAC;IAC9B,CAAC,cAAc,EAAE,gBAAgB,CAAC;IAClC,CAAC,UAAU,EAAE,YAAY,CAAC;IAC1B,CAAC,YAAY,EAAE,aAAa,CAAC;CAC9B,CAAC,CAAC;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAgC,IAAI,GAAG,CAAC;IACjE,CAAC,UAAU,EAAE,YAAY,CAAC;CAC3B,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Catalog } from '../../catalog/catalog.js';
2
+ import type { GVPConfig } from '../../config/schema.js';
3
+ import type { Diagnostic } from '../diagnostic.js';
4
+ /**
5
+ * Validates element content against Zod schemas (VAL-3).
6
+ *
7
+ * Schema validation happens at catalog construction via Zod schemas.
8
+ * This pass catches any elements that were loaded with passthrough
9
+ * and might have invalid dynamic fields after merge/inheritance.
10
+ */
11
+ export declare function schemaPass(catalog: Catalog, config: GVPConfig): Diagnostic[];
12
+ //# sourceMappingURL=schema-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-pass.d.ts","sourceRoot":"","sources":["../../../src/validation/passes/schema-pass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,GAAG,UAAU,EAAE,CAoC5E"}
@@ -0,0 +1,38 @@
1
+ import { createDiagnostic } from '../diagnostic.js';
2
+ const PASS_NAME = 'schema';
3
+ /**
4
+ * Validates element content against Zod schemas (VAL-3).
5
+ *
6
+ * Schema validation happens at catalog construction via Zod schemas.
7
+ * This pass catches any elements that were loaded with passthrough
8
+ * and might have invalid dynamic fields after merge/inheritance.
9
+ */
10
+ export function schemaPass(catalog, config) {
11
+ const diagnostics = [];
12
+ for (const element of catalog.getAllElements()) {
13
+ let schema;
14
+ try {
15
+ schema = catalog.registry.getElementSchema(element.categoryName, {
16
+ defaultTimezone: config.default_timezone,
17
+ });
18
+ }
19
+ catch {
20
+ // Unknown category — structural pass handles this
21
+ continue;
22
+ }
23
+ const result = schema.safeParse(element.data);
24
+ if (!result.success) {
25
+ for (const issue of result.error.issues) {
26
+ const fieldPath = issue.path.join('.');
27
+ diagnostics.push(createDiagnostic('E004', 'SCHEMA_VALIDATION', `Element ${element.toLibraryId()} field '${fieldPath}': ${issue.message}`, 'error', PASS_NAME, {
28
+ elementId: element.id,
29
+ documentPath: element.documentPath,
30
+ categoryName: element.categoryName,
31
+ fieldName: fieldPath || undefined,
32
+ }));
33
+ }
34
+ }
35
+ }
36
+ return diagnostics;
37
+ }
38
+ //# sourceMappingURL=schema-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-pass.js","sourceRoot":"","sources":["../../../src/validation/passes/schema-pass.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,SAAS,GAAG,QAAQ,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,MAAiB;IAC5D,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;QAC/C,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;gBAC/D,eAAe,EAAE,MAAM,CAAC,gBAAgB;aACzC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;YAClD,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACvC,WAAW,CAAC,IAAI,CAAC,gBAAgB,CAC/B,MAAM,EACN,mBAAmB,EACnB,WAAW,OAAO,CAAC,WAAW,EAAE,WAAW,SAAS,MAAM,KAAK,CAAC,OAAO,EAAE,EACzE,OAAO,EACP,SAAS,EACT;oBACE,SAAS,EAAE,OAAO,CAAC,EAAE;oBACrB,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,SAAS,EAAE,SAAS,IAAI,SAAS;iBAClC,CACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Catalog } from '../../catalog/catalog.js';
2
+ import type { GVPConfig } from '../../config/schema.js';
3
+ import type { Diagnostic } from '../diagnostic.js';
4
+ /**
5
+ * Semantic warnings W001-W006 (VAL-4).
6
+ */
7
+ export declare function semanticPass(catalog: Catalog, _config: GVPConfig): Diagnostic[];
8
+ //# sourceMappingURL=semantic-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-pass.d.ts","sourceRoot":"","sources":["../../../src/validation/passes/semantic-pass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAUnD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,GAAG,UAAU,EAAE,CA6K/E"}
@@ -0,0 +1,126 @@
1
+ import { createDiagnostic } from '../diagnostic.js';
2
+ import { isStale } from '../../provenance/staleness.js';
3
+ import { createRefParserRegistry, findParser } from '../../parsers/registry.js';
4
+ import { findProjectRoot } from '../../utils/project-root.js';
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ const PASS_NAME = 'semantic';
8
+ /**
9
+ * Semantic warnings W001-W006 (VAL-4).
10
+ */
11
+ export function semanticPass(catalog, _config) {
12
+ const diagnostics = [];
13
+ // Build lookup for resolving maps_to references
14
+ const elementLookup = new Map();
15
+ for (const el of catalog.getAllElements()) {
16
+ elementLookup.set(el.toLibraryId(), el);
17
+ elementLookup.set(el.hashKey(), el);
18
+ }
19
+ // W001: Empty maps_to on non-root active element (VAL-4)
20
+ for (const element of catalog.getAllElements()) {
21
+ if (element.status !== 'active')
22
+ continue;
23
+ if (element.maps_to.length > 0)
24
+ continue;
25
+ const catDef = catalog.registry.getByName(element.categoryName);
26
+ if (!catDef || catDef.is_root)
27
+ continue;
28
+ // Non-root active element with no maps_to
29
+ diagnostics.push(createDiagnostic('W001', 'EMPTY_MAPS_TO', `Element ${element.toLibraryId()} is a non-root active element with no maps_to references`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, categoryName: element.categoryName }));
30
+ }
31
+ // W002: Empty document (no active elements)
32
+ for (const doc of catalog.documents) {
33
+ const activeElements = doc.getAllElements().filter(e => e.status === 'active');
34
+ if (activeElements.length === 0) {
35
+ diagnostics.push(createDiagnostic('W002', 'EMPTY_DOCUMENT', `Document '${doc.name}' contains no active elements`, 'warning', PASS_NAME, { documentPath: doc.documentPath }));
36
+ }
37
+ }
38
+ // W005: Self-document-only mapping (DEC-5.5: always fires, suppress via diagnostic system)
39
+ for (const element of catalog.getAllElements()) {
40
+ if (element.status !== 'active')
41
+ continue;
42
+ if (element.maps_to.length === 0)
43
+ continue;
44
+ const catDef = catalog.registry.getByName(element.categoryName);
45
+ if (catDef?.is_root)
46
+ continue;
47
+ const allSelfDocument = element.maps_to.every(ref => {
48
+ const target = elementLookup.get(ref);
49
+ return target && target.documentPath === element.documentPath;
50
+ });
51
+ if (allSelfDocument) {
52
+ diagnostics.push(createDiagnostic('W005', 'SELF_DOCUMENT_MAPPING', `Element ${element.toLibraryId()} maps only to elements within its own document`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath }));
53
+ }
54
+ }
55
+ // W006: Staleness — element has unreviewed non-skip-review updates (DEC-4.7)
56
+ for (const element of catalog.getAllElements()) {
57
+ if (element.status !== 'active')
58
+ continue;
59
+ if (isStale(element)) {
60
+ diagnostics.push(createDiagnostic('W006', 'STALE_ELEMENT', `Element ${element.toLibraryId()} has unreviewed updates`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath }));
61
+ }
62
+ }
63
+ // W004: Orphan element — truly isolated (no incoming AND no outgoing edges)
64
+ {
65
+ // Build a set of all elements that are targets of some maps_to
66
+ const mappedToSet = new Set();
67
+ for (const el of catalog.getAllElements()) {
68
+ for (const ref of el.maps_to) {
69
+ mappedToSet.add(ref);
70
+ }
71
+ }
72
+ for (const element of catalog.getAllElements()) {
73
+ if (element.status !== 'active')
74
+ continue;
75
+ const catDef = catalog.registry.getByName(element.categoryName);
76
+ if (!catDef || catDef.is_root)
77
+ continue;
78
+ const libId = element.toLibraryId();
79
+ const hKey = element.hashKey();
80
+ const hasIncoming = mappedToSet.has(libId) || mappedToSet.has(hKey);
81
+ const hasOutgoing = element.maps_to.length > 0;
82
+ // Only flag if truly isolated — no edges in either direction
83
+ if (!hasIncoming && !hasOutgoing) {
84
+ diagnostics.push(createDiagnostic('W004', 'ORPHAN_ELEMENT', `Element ${libId} is isolated — nothing maps to it and it maps to nothing`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, categoryName: element.categoryName }));
85
+ }
86
+ }
87
+ }
88
+ // W010/W011: Ref file/identifier validation (DEC-10.5)
89
+ // Determine project root by walking up from first document's filePath looking for .git/
90
+ const projectRoot = findProjectRoot(catalog);
91
+ if (projectRoot) {
92
+ const parsers = createRefParserRegistry();
93
+ for (const element of catalog.getAllElements()) {
94
+ const refs = element.get('refs');
95
+ if (!refs || !Array.isArray(refs))
96
+ continue;
97
+ for (const ref of refs) {
98
+ const absPath = path.resolve(projectRoot, ref.file);
99
+ // W010: Ref file does not exist on disk
100
+ if (!fs.existsSync(absPath)) {
101
+ diagnostics.push(createDiagnostic('W010', 'REF_FILE_MISSING', `Element ${element.toLibraryId()} ref file does not exist: ${ref.file}`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, details: ref.file }));
102
+ continue;
103
+ }
104
+ // W011: Ref identifier not found in file
105
+ if (ref.identifier) {
106
+ const ext = path.extname(ref.file);
107
+ const parser = findParser(ext, parsers);
108
+ if (parser) {
109
+ try {
110
+ const content = fs.readFileSync(absPath, 'utf-8');
111
+ const block = parser.extractBlock(content, ref.identifier);
112
+ if (block === null) {
113
+ diagnostics.push(createDiagnostic('W011', 'REF_IDENTIFIER_MISSING', `Element ${element.toLibraryId()} ref identifier not found in ${ref.file}: ${ref.identifier}`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, details: `${ref.file}::${ref.identifier}` }));
114
+ }
115
+ }
116
+ catch {
117
+ // File read error — skip silently (W010 would have caught non-existent files)
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ return diagnostics;
125
+ }
126
+ //# sourceMappingURL=semantic-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-pass.js","sourceRoot":"","sources":["../../../src/validation/passes/semantic-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Catalog } from '../../catalog/catalog.js';
2
+ import type { GVPConfig } from '../../config/schema.js';
3
+ import type { Diagnostic } from '../diagnostic.js';
4
+ /**
5
+ * Broken references, undefined tags, ID gaps (VAL-1).
6
+ */
7
+ export declare function structuralPass(catalog: Catalog, _config: GVPConfig): Diagnostic[];
8
+ //# sourceMappingURL=structural-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-pass.d.ts","sourceRoot":"","sources":["../../../src/validation/passes/structural-pass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,GAAG,UAAU,EAAE,CA6LjF"}
@@ -0,0 +1,150 @@
1
+ import { createDiagnostic } from '../diagnostic.js';
2
+ const PASS_NAME = 'structural';
3
+ /**
4
+ * Broken references, undefined tags, ID gaps (VAL-1).
5
+ */
6
+ export function structuralPass(catalog, _config) {
7
+ const diagnostics = [];
8
+ // Build a set of all known element identifiers for fast lookup
9
+ const knownIds = new Set();
10
+ for (const element of catalog.getAllElements()) {
11
+ knownIds.add(element.toLibraryId());
12
+ knownIds.add(element.hashKey());
13
+ }
14
+ // E001: Broken maps_to references
15
+ for (const element of catalog.getAllElements()) {
16
+ for (const ref of element.maps_to) {
17
+ if (!knownIds.has(ref)) {
18
+ diagnostics.push(createDiagnostic('E001', 'BROKEN_REFERENCE', `Element ${element.toLibraryId()} references '${ref}' in maps_to, but no matching element was found`, 'error', PASS_NAME, { elementId: element.id, documentPath: element.documentPath }));
19
+ }
20
+ }
21
+ }
22
+ // W007: Undefined tags — element uses a tag not defined in its own library's documents (DEC-2.10: within-library scope)
23
+ // Group tag definitions by source (library)
24
+ const tagsBySource = new Map();
25
+ for (const doc of catalog.documents) {
26
+ const docTags = doc.getTagDefinitions();
27
+ if (!tagsBySource.has(doc.source)) {
28
+ tagsBySource.set(doc.source, new Set());
29
+ }
30
+ const sourceTagSet = tagsBySource.get(doc.source);
31
+ for (const tagName of Object.keys(docTags)) {
32
+ sourceTagSet.add(tagName);
33
+ }
34
+ }
35
+ for (const element of catalog.getAllElements()) {
36
+ const sourceDefinedTags = tagsBySource.get(element.source) ?? new Set();
37
+ for (const tag of element.tags) {
38
+ if (!sourceDefinedTags.has(tag)) {
39
+ diagnostics.push(createDiagnostic('W007', 'UNDEFINED_TAG', `Element ${element.toLibraryId()} uses tag '${tag}' which is not defined in its library's tag definitions`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath }));
40
+ }
41
+ }
42
+ }
43
+ // W009: ID sequence gaps within a category in a document
44
+ for (const doc of catalog.documents) {
45
+ // Group elements by category within this document
46
+ const categoryElements = new Map();
47
+ for (const element of doc.getAllElements()) {
48
+ const catDef = catalog.registry.getByName(element.categoryName);
49
+ if (!catDef)
50
+ continue;
51
+ const prefix = catDef.id_prefix;
52
+ // Extract numeric suffix from ID (e.g., "G3" -> 3)
53
+ const match = element.id.match(new RegExp(`^${escapeRegex(prefix)}(\\d+)$`));
54
+ if (!match)
55
+ continue;
56
+ const ids = categoryElements.get(element.categoryName) ?? [];
57
+ ids.push(element.id);
58
+ categoryElements.set(element.categoryName, ids);
59
+ }
60
+ for (const [categoryName, ids] of categoryElements) {
61
+ const catDef = catalog.registry.getByName(categoryName);
62
+ if (!catDef)
63
+ continue;
64
+ const prefix = catDef.id_prefix;
65
+ // Extract and sort numeric suffixes
66
+ const nums = ids
67
+ .map(id => {
68
+ const m = id.match(new RegExp(`^${escapeRegex(prefix)}(\\d+)$`));
69
+ return m ? parseInt(m[1], 10) : null;
70
+ })
71
+ .filter((n) => n !== null)
72
+ .sort((a, b) => a - b);
73
+ if (nums.length < 2)
74
+ continue;
75
+ // Check for gaps
76
+ for (let i = 1; i < nums.length; i++) {
77
+ if (nums[i] - nums[i - 1] > 1) {
78
+ const missingStart = nums[i - 1] + 1;
79
+ const missingEnd = nums[i] - 1;
80
+ const missingRange = missingStart === missingEnd
81
+ ? `${prefix}${missingStart}`
82
+ : `${prefix}${missingStart}-${prefix}${missingEnd}`;
83
+ diagnostics.push(createDiagnostic('W009', 'ID_SEQUENCE_GAP', `Document '${doc.name}' has gap in ${categoryName} IDs: missing ${missingRange}`, 'warning', PASS_NAME, { documentPath: doc.documentPath, categoryName }));
84
+ }
85
+ }
86
+ }
87
+ }
88
+ // E002: Duplicate element ID within a category in a document
89
+ for (const doc of catalog.documents) {
90
+ const seenIds = new Map(); // category -> Set<id>
91
+ for (const el of doc.getAllElements()) {
92
+ if (!seenIds.has(el.categoryName))
93
+ seenIds.set(el.categoryName, new Set());
94
+ const ids = seenIds.get(el.categoryName);
95
+ if (ids.has(el.id)) {
96
+ diagnostics.push(createDiagnostic('E002', 'DUPLICATE_ELEMENT_ID', `Document '${doc.name}' has duplicate ${el.categoryName} element ID '${el.id}'`, 'error', PASS_NAME, { elementId: el.id, documentPath: doc.documentPath, categoryName: el.categoryName }));
97
+ }
98
+ ids.add(el.id);
99
+ }
100
+ }
101
+ // W008: Duplicate category definition within a single library (same source)
102
+ {
103
+ const catDefsBySource = new Map(); // source -> (catName -> docPaths[])
104
+ for (const doc of catalog.documents) {
105
+ const docCats = doc.getCategoryDefinitions();
106
+ for (const catName of Object.keys(docCats)) {
107
+ if (!catDefsBySource.has(doc.source))
108
+ catDefsBySource.set(doc.source, new Map());
109
+ const sourceCats = catDefsBySource.get(doc.source);
110
+ if (!sourceCats.has(catName))
111
+ sourceCats.set(catName, []);
112
+ sourceCats.get(catName).push(doc.documentPath);
113
+ }
114
+ }
115
+ for (const [, sourceCats] of catDefsBySource) {
116
+ for (const [catName, docPaths] of sourceCats) {
117
+ if (docPaths.length > 1) {
118
+ diagnostics.push(createDiagnostic('W008', 'DUPLICATE_CATEGORY_DEF', `Category '${catName}' is defined in multiple documents within the same library: ${docPaths.join(', ')}`, 'warning', PASS_NAME, { categoryName: catName, details: docPaths.join(', ') }));
119
+ }
120
+ }
121
+ }
122
+ }
123
+ // E003: Broken inheritance — document references a parent that doesn't exist
124
+ const knownDocPaths = new Set();
125
+ for (const doc of catalog.documents) {
126
+ knownDocPaths.add(doc.documentPath);
127
+ knownDocPaths.add(doc.source + ':' + doc.documentPath);
128
+ }
129
+ for (const doc of catalog.documents) {
130
+ if (!doc.meta.inherits)
131
+ continue;
132
+ const inherits = doc.meta.inherits;
133
+ for (const parent of inherits) {
134
+ const parentPath = typeof parent === 'string' ? parent : parent.source;
135
+ // The parent should be in the catalog's documents if inheritance resolved correctly.
136
+ // If it's listed but not found, it's a broken reference.
137
+ const found = catalog.documents.some(d => d.documentPath === parentPath ||
138
+ d.source + ':' + d.documentPath === parentPath);
139
+ if (!found) {
140
+ diagnostics.push(createDiagnostic('E003', 'BROKEN_INHERITANCE', `Document '${doc.name}' inherits from '${parentPath}' which does not exist in the catalog`, 'error', PASS_NAME, { documentPath: doc.documentPath }));
141
+ }
142
+ }
143
+ }
144
+ return diagnostics;
145
+ }
146
+ /** Escape regex special characters in a string */
147
+ function escapeRegex(str) {
148
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
149
+ }
150
+ //# sourceMappingURL=structural-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-pass.js","sourceRoot":"","sources":["../../../src/validation/passes/structural-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Catalog } from '../../catalog/catalog.js';
2
+ import type { GVPConfig } from '../../config/schema.js';
3
+ import type { Diagnostic } from '../diagnostic.js';
4
+ /**
5
+ * Mapping rules compliance (VAL-2).
6
+ * Checks that non-root elements map to appropriate categories per mapping_rules.
7
+ */
8
+ export declare function traceabilityPass(catalog: Catalog, _config: GVPConfig): Diagnostic[];
9
+ //# sourceMappingURL=traceability-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceability-pass.d.ts","sourceRoot":"","sources":["../../../src/validation/passes/traceability-pass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,GAAG,UAAU,EAAE,CAqGnF"}
@@ -0,0 +1,87 @@
1
+ import { createDiagnostic } from '../diagnostic.js';
2
+ const PASS_NAME = 'traceability';
3
+ /**
4
+ * Mapping rules compliance (VAL-2).
5
+ * Checks that non-root elements map to appropriate categories per mapping_rules.
6
+ */
7
+ export function traceabilityPass(catalog, _config) {
8
+ const diagnostics = [];
9
+ // Build lookup: libraryId/hashKey -> element
10
+ const elementLookup = new Map();
11
+ for (const el of catalog.getAllElements()) {
12
+ elementLookup.set(el.toLibraryId(), el);
13
+ elementLookup.set(el.hashKey(), el);
14
+ }
15
+ for (const element of catalog.getAllElements()) {
16
+ if (element.status === 'deprecated' || element.status === 'rejected')
17
+ continue;
18
+ const catDef = catalog.registry.getByName(element.categoryName);
19
+ if (!catDef || catDef.is_root)
20
+ continue;
21
+ if (!catDef.mapping_rules || catDef.mapping_rules.length === 0)
22
+ continue;
23
+ // mapping_rules is OR of AND groups: [[goal, value], [principle]]
24
+ // means element must map to (goal AND value) OR (principle)
25
+ const mappedCategories = new Set();
26
+ for (const ref of element.maps_to) {
27
+ const target = elementLookup.get(ref);
28
+ if (target) {
29
+ mappedCategories.add(target.categoryName);
30
+ }
31
+ }
32
+ const satisfiesRules = catDef.mapping_rules.some(andGroup => andGroup.every(requiredCat => mappedCategories.has(requiredCat)));
33
+ // Note: elements with empty maps_to are handled by W001 (EMPTY_MAPS_TO) in the
34
+ // semantic pass, not W003 here. This is intentional delegation — W003 only fires
35
+ // when maps_to is non-empty but doesn't satisfy the mapping_rules for the category.
36
+ if (!satisfiesRules && element.maps_to.length > 0) {
37
+ diagnostics.push(createDiagnostic('W003', 'MAPPING_RULES_VIOLATION', `Element ${element.toLibraryId()} does not satisfy mapping_rules for category '${element.categoryName}'`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, categoryName: element.categoryName }));
38
+ }
39
+ }
40
+ // W014: Transitive traceability — non-root active elements must trace to at least one root element (R3)
41
+ {
42
+ // Identify root categories
43
+ const rootCategories = new Set();
44
+ for (const catName of catalog.registry.categoryNames) {
45
+ const catDef = catalog.registry.getByName(catName);
46
+ if (catDef?.is_root)
47
+ rootCategories.add(catName);
48
+ }
49
+ for (const element of catalog.getAllElements()) {
50
+ if (element.status === 'deprecated' || element.status === 'rejected')
51
+ continue;
52
+ const catDef = catalog.registry.getByName(element.categoryName);
53
+ if (!catDef || catDef.is_root)
54
+ continue;
55
+ if (element.maps_to.length === 0)
56
+ continue; // W001 handles this
57
+ // BFS/DFS walk through maps_to graph to find a root element
58
+ const visited = new Set();
59
+ const queue = [element.hashKey()];
60
+ let foundRoot = false;
61
+ while (queue.length > 0) {
62
+ const current = queue.pop();
63
+ if (visited.has(current))
64
+ continue;
65
+ visited.add(current);
66
+ const currentEl = elementLookup.get(current);
67
+ if (!currentEl)
68
+ continue;
69
+ if (rootCategories.has(currentEl.categoryName)) {
70
+ foundRoot = true;
71
+ break;
72
+ }
73
+ for (const ref of currentEl.maps_to) {
74
+ const target = elementLookup.get(ref);
75
+ if (target && !visited.has(target.hashKey())) {
76
+ queue.push(target.hashKey());
77
+ }
78
+ }
79
+ }
80
+ if (!foundRoot) {
81
+ diagnostics.push(createDiagnostic('W014', 'NO_ROOT_TRACE', `Element ${element.toLibraryId()} cannot trace to any root element transitively`, 'warning', PASS_NAME, { elementId: element.id, documentPath: element.documentPath, categoryName: element.categoryName }));
82
+ }
83
+ }
84
+ }
85
+ return diagnostics;
86
+ }
87
+ //# sourceMappingURL=traceability-pass.js.map