@transitrix/diagrams 1.0.0

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 (541) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/__tests__/edge-path.test.d.ts +1 -0
  4. package/dist/__tests__/edge-path.test.js +39 -0
  5. package/dist/__tests__/scope.test.d.ts +1 -0
  6. package/dist/__tests__/scope.test.js +23 -0
  7. package/dist/__tests__/yaml-normalize.test.d.ts +1 -0
  8. package/dist/__tests__/yaml-normalize.test.js +148 -0
  9. package/dist/activities/__tests__/cpm.test.d.ts +1 -0
  10. package/dist/activities/__tests__/cpm.test.js +146 -0
  11. package/dist/activities/__tests__/gantt.test.d.ts +1 -0
  12. package/dist/activities/__tests__/gantt.test.js +224 -0
  13. package/dist/activities/__tests__/layout.test.d.ts +1 -0
  14. package/dist/activities/__tests__/layout.test.js +98 -0
  15. package/dist/activities/__tests__/validate.test.d.ts +1 -0
  16. package/dist/activities/__tests__/validate.test.js +363 -0
  17. package/dist/activities/cpm.d.ts +2 -0
  18. package/dist/activities/cpm.js +86 -0
  19. package/dist/activities/gantt.d.ts +6 -0
  20. package/dist/activities/gantt.js +250 -0
  21. package/dist/activities/index.d.ts +5 -0
  22. package/dist/activities/index.js +4 -0
  23. package/dist/activities/layout.d.ts +2 -0
  24. package/dist/activities/layout.js +103 -0
  25. package/dist/activities/types.d.ts +125 -0
  26. package/dist/activities/types.js +1 -0
  27. package/dist/activities/validate.d.ts +2 -0
  28. package/dist/activities/validate.js +326 -0
  29. package/dist/activity-card/__tests__/example.test.d.ts +1 -0
  30. package/dist/activity-card/__tests__/example.test.js +56 -0
  31. package/dist/activity-card/__tests__/layout.test.d.ts +1 -0
  32. package/dist/activity-card/__tests__/layout.test.js +57 -0
  33. package/dist/activity-card/__tests__/resolver.test.d.ts +1 -0
  34. package/dist/activity-card/__tests__/resolver.test.js +146 -0
  35. package/dist/activity-card/__tests__/validate.test.d.ts +1 -0
  36. package/dist/activity-card/__tests__/validate.test.js +116 -0
  37. package/dist/activity-card/index.d.ts +5 -0
  38. package/dist/activity-card/index.js +3 -0
  39. package/dist/activity-card/layout.d.ts +7 -0
  40. package/dist/activity-card/layout.js +167 -0
  41. package/dist/activity-card/resolver.d.ts +7 -0
  42. package/dist/activity-card/resolver.js +310 -0
  43. package/dist/activity-card/types.d.ts +175 -0
  44. package/dist/activity-card/types.js +20 -0
  45. package/dist/activity-card/validate.d.ts +3 -0
  46. package/dist/activity-card/validate.js +145 -0
  47. package/dist/actor/__tests__/validate.test.d.ts +1 -0
  48. package/dist/actor/__tests__/validate.test.js +57 -0
  49. package/dist/actor/index.d.ts +3 -0
  50. package/dist/actor/index.js +2 -0
  51. package/dist/actor/types.d.ts +20 -0
  52. package/dist/actor/types.js +4 -0
  53. package/dist/actor/validate.d.ts +2 -0
  54. package/dist/actor/validate.js +34 -0
  55. package/dist/applications/__tests__/validate.test.d.ts +1 -0
  56. package/dist/applications/__tests__/validate.test.js +223 -0
  57. package/dist/applications/index.d.ts +2 -0
  58. package/dist/applications/index.js +1 -0
  59. package/dist/applications/types.d.ts +39 -0
  60. package/dist/applications/types.js +1 -0
  61. package/dist/applications/validate.d.ts +3 -0
  62. package/dist/applications/validate.js +109 -0
  63. package/dist/assertion/__tests__/example.test.d.ts +1 -0
  64. package/dist/assertion/__tests__/example.test.js +32 -0
  65. package/dist/assertion/__tests__/validate.test.d.ts +1 -0
  66. package/dist/assertion/__tests__/validate.test.js +130 -0
  67. package/dist/assertion/index.d.ts +4 -0
  68. package/dist/assertion/index.js +2 -0
  69. package/dist/assertion/types.d.ts +43 -0
  70. package/dist/assertion/types.js +7 -0
  71. package/dist/assertion/validate.d.ts +9 -0
  72. package/dist/assertion/validate.js +137 -0
  73. package/dist/blocks/__tests__/layout.test.d.ts +1 -0
  74. package/dist/blocks/__tests__/layout.test.js +153 -0
  75. package/dist/blocks/__tests__/validate.test.d.ts +1 -0
  76. package/dist/blocks/__tests__/validate.test.js +235 -0
  77. package/dist/blocks/index.d.ts +4 -0
  78. package/dist/blocks/index.js +2 -0
  79. package/dist/blocks/layout.d.ts +4 -0
  80. package/dist/blocks/layout.js +145 -0
  81. package/dist/blocks/types.d.ts +56 -0
  82. package/dist/blocks/types.js +1 -0
  83. package/dist/blocks/validate.d.ts +9 -0
  84. package/dist/blocks/validate.js +186 -0
  85. package/dist/capability-map/__tests__/validate.test.d.ts +1 -0
  86. package/dist/capability-map/__tests__/validate.test.js +212 -0
  87. package/dist/capability-map/index.d.ts +2 -0
  88. package/dist/capability-map/index.js +1 -0
  89. package/dist/capability-map/types.d.ts +26 -0
  90. package/dist/capability-map/types.js +1 -0
  91. package/dist/capability-map/validate.d.ts +3 -0
  92. package/dist/capability-map/validate.js +103 -0
  93. package/dist/change/__tests__/validate.test.d.ts +1 -0
  94. package/dist/change/__tests__/validate.test.js +73 -0
  95. package/dist/change/index.d.ts +2 -0
  96. package/dist/change/index.js +1 -0
  97. package/dist/change/types.d.ts +17 -0
  98. package/dist/change/types.js +3 -0
  99. package/dist/change/validate.d.ts +2 -0
  100. package/dist/change/validate.js +57 -0
  101. package/dist/compliance/__tests__/classify.test.d.ts +1 -0
  102. package/dist/compliance/__tests__/classify.test.js +24 -0
  103. package/dist/compliance/__tests__/confidence.test.d.ts +1 -0
  104. package/dist/compliance/__tests__/confidence.test.js +78 -0
  105. package/dist/compliance/__tests__/coverage-metric.test.d.ts +1 -0
  106. package/dist/compliance/__tests__/coverage-metric.test.js +164 -0
  107. package/dist/compliance/__tests__/demo-scenario.test.d.ts +1 -0
  108. package/dist/compliance/__tests__/demo-scenario.test.js +226 -0
  109. package/dist/compliance/__tests__/example.test.d.ts +1 -0
  110. package/dist/compliance/__tests__/example.test.js +51 -0
  111. package/dist/compliance/__tests__/gap-report.test.d.ts +1 -0
  112. package/dist/compliance/__tests__/gap-report.test.js +113 -0
  113. package/dist/compliance/__tests__/html.test.d.ts +1 -0
  114. package/dist/compliance/__tests__/html.test.js +122 -0
  115. package/dist/compliance/__tests__/impact.test.d.ts +1 -0
  116. package/dist/compliance/__tests__/impact.test.js +410 -0
  117. package/dist/compliance/__tests__/markdown.test.d.ts +1 -0
  118. package/dist/compliance/__tests__/markdown.test.js +85 -0
  119. package/dist/compliance/__tests__/views.test.d.ts +1 -0
  120. package/dist/compliance/__tests__/views.test.js +59 -0
  121. package/dist/compliance/classify.d.ts +27 -0
  122. package/dist/compliance/classify.js +60 -0
  123. package/dist/compliance/confidence.d.ts +27 -0
  124. package/dist/compliance/confidence.js +43 -0
  125. package/dist/compliance/coverage-metric.d.ts +74 -0
  126. package/dist/compliance/coverage-metric.js +181 -0
  127. package/dist/compliance/gap-report.d.ts +20 -0
  128. package/dist/compliance/gap-report.js +64 -0
  129. package/dist/compliance/html.d.ts +22 -0
  130. package/dist/compliance/html.js +256 -0
  131. package/dist/compliance/impact.d.ts +251 -0
  132. package/dist/compliance/impact.js +464 -0
  133. package/dist/compliance/index.d.ts +16 -0
  134. package/dist/compliance/index.js +9 -0
  135. package/dist/compliance/markdown.d.ts +18 -0
  136. package/dist/compliance/markdown.js +129 -0
  137. package/dist/compliance/reverse-index.d.ts +8 -0
  138. package/dist/compliance/reverse-index.js +30 -0
  139. package/dist/compliance/types.d.ts +98 -0
  140. package/dist/compliance/types.js +5 -0
  141. package/dist/compliance/views.d.ts +14 -0
  142. package/dist/compliance/views.js +35 -0
  143. package/dist/compliance-matrix/__tests__/build.test.d.ts +1 -0
  144. package/dist/compliance-matrix/__tests__/build.test.js +183 -0
  145. package/dist/compliance-matrix/__tests__/example.test.d.ts +1 -0
  146. package/dist/compliance-matrix/__tests__/example.test.js +49 -0
  147. package/dist/compliance-matrix/build.d.ts +18 -0
  148. package/dist/compliance-matrix/build.js +0 -0
  149. package/dist/compliance-matrix/index.d.ts +2 -0
  150. package/dist/compliance-matrix/index.js +1 -0
  151. package/dist/compliance-matrix/types.d.ts +86 -0
  152. package/dist/compliance-matrix/types.js +8 -0
  153. package/dist/confidence/__tests__/score.test.d.ts +1 -0
  154. package/dist/confidence/__tests__/score.test.js +188 -0
  155. package/dist/confidence/index.d.ts +2 -0
  156. package/dist/confidence/index.js +1 -0
  157. package/dist/confidence/score.d.ts +62 -0
  158. package/dist/confidence/score.js +215 -0
  159. package/dist/confidence/types.d.ts +79 -0
  160. package/dist/confidence/types.js +6 -0
  161. package/dist/edge-path.d.ts +18 -0
  162. package/dist/edge-path.js +35 -0
  163. package/dist/element-envelope.d.ts +15 -0
  164. package/dist/element-envelope.js +55 -0
  165. package/dist/factor/__tests__/validate.test.d.ts +1 -0
  166. package/dist/factor/__tests__/validate.test.js +83 -0
  167. package/dist/factor/index.d.ts +3 -0
  168. package/dist/factor/index.js +2 -0
  169. package/dist/factor/types.d.ts +23 -0
  170. package/dist/factor/types.js +6 -0
  171. package/dist/factor/validate.d.ts +2 -0
  172. package/dist/factor/validate.js +69 -0
  173. package/dist/fgca/__tests__/chain-table.test.d.ts +1 -0
  174. package/dist/fgca/__tests__/chain-table.test.js +158 -0
  175. package/dist/fgca/__tests__/layout.test.d.ts +1 -0
  176. package/dist/fgca/__tests__/layout.test.js +140 -0
  177. package/dist/fgca/__tests__/parse-canonical.test.d.ts +1 -0
  178. package/dist/fgca/__tests__/parse-canonical.test.js +224 -0
  179. package/dist/fgca/__tests__/preview-layout.test.d.ts +1 -0
  180. package/dist/fgca/__tests__/preview-layout.test.js +106 -0
  181. package/dist/fgca/__tests__/validate.test.d.ts +1 -0
  182. package/dist/fgca/__tests__/validate.test.js +125 -0
  183. package/dist/fgca/chain-table.d.ts +36 -0
  184. package/dist/fgca/chain-table.js +177 -0
  185. package/dist/fgca/index.d.ts +16 -0
  186. package/dist/fgca/index.js +11 -0
  187. package/dist/fgca/layout.d.ts +27 -0
  188. package/dist/fgca/layout.js +156 -0
  189. package/dist/fgca/nodeTypes.d.ts +6 -0
  190. package/dist/fgca/nodeTypes.js +10 -0
  191. package/dist/fgca/nodes/FGCAActivityNode.d.ts +13 -0
  192. package/dist/fgca/nodes/FGCAActivityNode.js +35 -0
  193. package/dist/fgca/nodes/FGCAChangeNode.d.ts +12 -0
  194. package/dist/fgca/nodes/FGCAChangeNode.js +35 -0
  195. package/dist/fgca/nodes/FGCAFactorNode.d.ts +12 -0
  196. package/dist/fgca/nodes/FGCAFactorNode.js +35 -0
  197. package/dist/fgca/nodes/FGCAGoalNode.d.ts +14 -0
  198. package/dist/fgca/nodes/FGCAGoalNode.js +40 -0
  199. package/dist/fgca/parse-canonical.d.ts +58 -0
  200. package/dist/fgca/parse-canonical.js +339 -0
  201. package/dist/fgca/preview-layout.d.ts +87 -0
  202. package/dist/fgca/preview-layout.js +122 -0
  203. package/dist/fgca/types.d.ts +39 -0
  204. package/dist/fgca/types.js +7 -0
  205. package/dist/fgca/validate.d.ts +14 -0
  206. package/dist/fgca/validate.js +108 -0
  207. package/dist/geometry.d.ts +7 -0
  208. package/dist/geometry.js +2 -0
  209. package/dist/goals/__tests__/layout.test.d.ts +1 -0
  210. package/dist/goals/__tests__/layout.test.js +153 -0
  211. package/dist/goals/__tests__/mutations.test.d.ts +1 -0
  212. package/dist/goals/__tests__/mutations.test.js +95 -0
  213. package/dist/goals/__tests__/parse-canonical.test.d.ts +1 -0
  214. package/dist/goals/__tests__/parse-canonical.test.js +129 -0
  215. package/dist/goals/__tests__/validate.test.d.ts +1 -0
  216. package/dist/goals/__tests__/validate.test.js +183 -0
  217. package/dist/goals/index.d.ts +6 -0
  218. package/dist/goals/index.js +4 -0
  219. package/dist/goals/layout.d.ts +11 -0
  220. package/dist/goals/layout.js +147 -0
  221. package/dist/goals/mutations.d.ts +6 -0
  222. package/dist/goals/mutations.js +116 -0
  223. package/dist/goals/parse-canonical.d.ts +29 -0
  224. package/dist/goals/parse-canonical.js +257 -0
  225. package/dist/goals/types.d.ts +71 -0
  226. package/dist/goals/types.js +1 -0
  227. package/dist/goals/validate.d.ts +2 -0
  228. package/dist/goals/validate.js +122 -0
  229. package/dist/index.d.ts +23 -0
  230. package/dist/index.js +23 -0
  231. package/dist/issues/__tests__/layout.test.d.ts +1 -0
  232. package/dist/issues/__tests__/layout.test.js +62 -0
  233. package/dist/issues/__tests__/validate.test.d.ts +1 -0
  234. package/dist/issues/__tests__/validate.test.js +82 -0
  235. package/dist/issues/index.d.ts +4 -0
  236. package/dist/issues/index.js +2 -0
  237. package/dist/issues/layout.d.ts +10 -0
  238. package/dist/issues/layout.js +82 -0
  239. package/dist/issues/types.d.ts +61 -0
  240. package/dist/issues/types.js +6 -0
  241. package/dist/issues/validate.d.ts +3 -0
  242. package/dist/issues/validate.js +143 -0
  243. package/dist/process-blueprint/__tests__/compliance-lane.test.d.ts +1 -0
  244. package/dist/process-blueprint/__tests__/compliance-lane.test.js +272 -0
  245. package/dist/process-blueprint/__tests__/layout.test.d.ts +1 -0
  246. package/dist/process-blueprint/__tests__/layout.test.js +159 -0
  247. package/dist/process-blueprint/__tests__/validate.test.d.ts +1 -0
  248. package/dist/process-blueprint/__tests__/validate.test.js +280 -0
  249. package/dist/process-blueprint/index.d.ts +4 -0
  250. package/dist/process-blueprint/index.js +2 -0
  251. package/dist/process-blueprint/layout.d.ts +2 -0
  252. package/dist/process-blueprint/layout.js +416 -0
  253. package/dist/process-blueprint/types.d.ts +220 -0
  254. package/dist/process-blueprint/types.js +1 -0
  255. package/dist/process-blueprint/validate.d.ts +3 -0
  256. package/dist/process-blueprint/validate.js +165 -0
  257. package/dist/process-map/__tests__/validate.test.d.ts +1 -0
  258. package/dist/process-map/__tests__/validate.test.js +199 -0
  259. package/dist/process-map/index.d.ts +2 -0
  260. package/dist/process-map/index.js +1 -0
  261. package/dist/process-map/types.d.ts +32 -0
  262. package/dist/process-map/types.js +1 -0
  263. package/dist/process-map/validate.d.ts +3 -0
  264. package/dist/process-map/validate.js +115 -0
  265. package/dist/products/__tests__/validate.test.d.ts +1 -0
  266. package/dist/products/__tests__/validate.test.js +210 -0
  267. package/dist/products/index.d.ts +2 -0
  268. package/dist/products/index.js +1 -0
  269. package/dist/products/types.d.ts +28 -0
  270. package/dist/products/types.js +1 -0
  271. package/dist/products/validate.d.ts +3 -0
  272. package/dist/products/validate.js +93 -0
  273. package/dist/repo-validate/__tests__/validate-repo.test.d.ts +1 -0
  274. package/dist/repo-validate/__tests__/validate-repo.test.js +132 -0
  275. package/dist/repo-validate/index.d.ts +2 -0
  276. package/dist/repo-validate/index.js +1 -0
  277. package/dist/repo-validate/types.d.ts +34 -0
  278. package/dist/repo-validate/types.js +14 -0
  279. package/dist/repo-validate/validate-repo.d.ts +8 -0
  280. package/dist/repo-validate/validate-repo.js +189 -0
  281. package/dist/requirement/__tests__/example.test.d.ts +1 -0
  282. package/dist/requirement/__tests__/example.test.js +21 -0
  283. package/dist/requirement/__tests__/validate.test.d.ts +1 -0
  284. package/dist/requirement/__tests__/validate.test.js +80 -0
  285. package/dist/requirement/index.d.ts +4 -0
  286. package/dist/requirement/index.js +2 -0
  287. package/dist/requirement/types.d.ts +25 -0
  288. package/dist/requirement/types.js +4 -0
  289. package/dist/requirement/validate.d.ts +7 -0
  290. package/dist/requirement/validate.js +81 -0
  291. package/dist/scenarios/__tests__/validate.test.d.ts +1 -0
  292. package/dist/scenarios/__tests__/validate.test.js +183 -0
  293. package/dist/scenarios/index.d.ts +2 -0
  294. package/dist/scenarios/index.js +1 -0
  295. package/dist/scenarios/types.d.ts +45 -0
  296. package/dist/scenarios/types.js +1 -0
  297. package/dist/scenarios/validate.d.ts +3 -0
  298. package/dist/scenarios/validate.js +110 -0
  299. package/dist/schema-version.d.ts +16 -0
  300. package/dist/schema-version.js +16 -0
  301. package/dist/scope.d.ts +23 -0
  302. package/dist/scope.js +38 -0
  303. package/dist/stakeholder/__tests__/validate.test.d.ts +1 -0
  304. package/dist/stakeholder/__tests__/validate.test.js +86 -0
  305. package/dist/stakeholder/index.d.ts +3 -0
  306. package/dist/stakeholder/index.js +2 -0
  307. package/dist/stakeholder/types.d.ts +24 -0
  308. package/dist/stakeholder/types.js +5 -0
  309. package/dist/stakeholder/validate.d.ts +2 -0
  310. package/dist/stakeholder/validate.js +58 -0
  311. package/dist/target-state/__tests__/validate.test.d.ts +1 -0
  312. package/dist/target-state/__tests__/validate.test.js +62 -0
  313. package/dist/target-state/index.d.ts +2 -0
  314. package/dist/target-state/index.js +1 -0
  315. package/dist/target-state/types.d.ts +18 -0
  316. package/dist/target-state/types.js +7 -0
  317. package/dist/target-state/validate.d.ts +2 -0
  318. package/dist/target-state/validate.js +61 -0
  319. package/dist/theme/index.d.ts +4 -0
  320. package/dist/theme/index.js +2 -0
  321. package/dist/theme/themes.d.ts +16 -0
  322. package/dist/theme/themes.js +213 -0
  323. package/dist/theme/tokens.d.ts +158 -0
  324. package/dist/theme/tokens.js +105 -0
  325. package/dist/typed-id.d.ts +20 -0
  326. package/dist/typed-id.js +38 -0
  327. package/dist/validation-types.d.ts +34 -0
  328. package/dist/validation-types.js +1 -0
  329. package/dist/webview/__tests__/entry-notations.test.d.ts +1 -0
  330. package/dist/webview/__tests__/entry-notations.test.js +62 -0
  331. package/dist/webview/__tests__/entry.test.d.ts +1 -0
  332. package/dist/webview/__tests__/entry.test.js +56 -0
  333. package/dist/webview/__tests__/render-goals.test.d.ts +1 -0
  334. package/dist/webview/__tests__/render-goals.test.js +65 -0
  335. package/dist/webview/entry.d.ts +38 -0
  336. package/dist/webview/entry.js +182 -0
  337. package/dist/webview/render-activities.d.ts +24 -0
  338. package/dist/webview/render-activities.js +127 -0
  339. package/dist/webview/render-activity-card.d.ts +5 -0
  340. package/dist/webview/render-activity-card.js +168 -0
  341. package/dist/webview/render-applications.d.ts +11 -0
  342. package/dist/webview/render-applications.js +105 -0
  343. package/dist/webview/render-blocks.d.ts +5 -0
  344. package/dist/webview/render-blocks.js +71 -0
  345. package/dist/webview/render-capability-map.d.ts +7 -0
  346. package/dist/webview/render-capability-map.js +88 -0
  347. package/dist/webview/render-fgca.d.ts +8 -0
  348. package/dist/webview/render-fgca.js +94 -0
  349. package/dist/webview/render-goals.d.ts +6 -0
  350. package/dist/webview/render-goals.js +92 -0
  351. package/dist/webview/render-process-blueprint.d.ts +5 -0
  352. package/dist/webview/render-process-blueprint.js +135 -0
  353. package/dist/webview/render-process-map.d.ts +7 -0
  354. package/dist/webview/render-process-map.js +82 -0
  355. package/dist/webview/render-products.d.ts +7 -0
  356. package/dist/webview/render-products.js +81 -0
  357. package/dist/webview/render-scenarios.d.ts +7 -0
  358. package/dist/webview/render-scenarios.js +75 -0
  359. package/dist/webview/render-util.d.ts +16 -0
  360. package/dist/webview/render-util.js +31 -0
  361. package/dist/webview/transitrix-render.css +323 -0
  362. package/dist/webview/transitrix-render.js +6452 -0
  363. package/dist/webview/transitrix-render.js.map +7 -0
  364. package/dist/yaml-normalize.d.ts +20 -0
  365. package/dist/yaml-normalize.js +57 -0
  366. package/package.json +40 -0
  367. package/src/__tests__/edge-path.test.ts +46 -0
  368. package/src/__tests__/scope.test.ts +27 -0
  369. package/src/__tests__/yaml-normalize.test.ts +158 -0
  370. package/src/activities/__tests__/cpm.test.ts +164 -0
  371. package/src/activities/__tests__/gantt.test.ts +245 -0
  372. package/src/activities/__tests__/layout.test.ts +112 -0
  373. package/src/activities/__tests__/validate.test.ts +409 -0
  374. package/src/activities/cpm.ts +95 -0
  375. package/src/activities/gantt.ts +276 -0
  376. package/src/activities/index.ts +28 -0
  377. package/src/activities/layout.ts +112 -0
  378. package/src/activities/types.ts +148 -0
  379. package/src/activities/validate.ts +357 -0
  380. package/src/activity-card/__tests__/example.test.ts +66 -0
  381. package/src/activity-card/__tests__/layout.test.ts +63 -0
  382. package/src/activity-card/__tests__/resolver.test.ts +161 -0
  383. package/src/activity-card/__tests__/validate.test.ts +131 -0
  384. package/src/activity-card/index.ts +32 -0
  385. package/src/activity-card/layout.ts +194 -0
  386. package/src/activity-card/resolver.ts +337 -0
  387. package/src/activity-card/types.ts +237 -0
  388. package/src/activity-card/validate.ts +158 -0
  389. package/src/actor/__tests__/validate.test.ts +67 -0
  390. package/src/actor/index.ts +3 -0
  391. package/src/actor/types.ts +29 -0
  392. package/src/actor/validate.ts +38 -0
  393. package/src/applications/__tests__/validate.test.ts +256 -0
  394. package/src/applications/index.ts +11 -0
  395. package/src/applications/types.ts +43 -0
  396. package/src/applications/validate.ts +131 -0
  397. package/src/assertion/__tests__/example.test.ts +37 -0
  398. package/src/assertion/__tests__/validate.test.ts +142 -0
  399. package/src/assertion/index.ts +12 -0
  400. package/src/assertion/types.ts +58 -0
  401. package/src/assertion/validate.ts +145 -0
  402. package/src/blocks/__tests__/layout.test.ts +169 -0
  403. package/src/blocks/__tests__/validate.test.ts +260 -0
  404. package/src/blocks/index.ts +17 -0
  405. package/src/blocks/layout.ts +186 -0
  406. package/src/blocks/types.ts +62 -0
  407. package/src/blocks/validate.ts +206 -0
  408. package/src/capability-map/__tests__/validate.test.ts +238 -0
  409. package/src/capability-map/index.ts +8 -0
  410. package/src/capability-map/types.ts +29 -0
  411. package/src/capability-map/validate.ts +127 -0
  412. package/src/change/__tests__/validate.test.ts +88 -0
  413. package/src/change/index.ts +2 -0
  414. package/src/change/types.ts +23 -0
  415. package/src/change/validate.ts +61 -0
  416. package/src/compliance/__tests__/classify.test.ts +27 -0
  417. package/src/compliance/__tests__/confidence.test.ts +98 -0
  418. package/src/compliance/__tests__/coverage-metric.test.ts +188 -0
  419. package/src/compliance/__tests__/demo-scenario.test.ts +273 -0
  420. package/src/compliance/__tests__/example.test.ts +57 -0
  421. package/src/compliance/__tests__/gap-report.test.ts +129 -0
  422. package/src/compliance/__tests__/html.test.ts +142 -0
  423. package/src/compliance/__tests__/impact.test.ts +482 -0
  424. package/src/compliance/__tests__/markdown.test.ts +95 -0
  425. package/src/compliance/__tests__/views.test.ts +64 -0
  426. package/src/compliance/classify.ts +84 -0
  427. package/src/compliance/confidence.ts +69 -0
  428. package/src/compliance/coverage-metric.ts +263 -0
  429. package/src/compliance/gap-report.ts +94 -0
  430. package/src/compliance/html.ts +295 -0
  431. package/src/compliance/impact.ts +677 -0
  432. package/src/compliance/index.ts +56 -0
  433. package/src/compliance/markdown.ts +135 -0
  434. package/src/compliance/reverse-index.ts +33 -0
  435. package/src/compliance/types.ts +120 -0
  436. package/src/compliance/views.ts +46 -0
  437. package/src/compliance-matrix/__tests__/build.test.ts +200 -0
  438. package/src/compliance-matrix/__tests__/example.test.ts +57 -0
  439. package/src/compliance-matrix/build.ts +0 -0
  440. package/src/compliance-matrix/index.ts +11 -0
  441. package/src/compliance-matrix/types.ts +102 -0
  442. package/src/confidence/__tests__/score.test.ts +254 -0
  443. package/src/confidence/index.ts +21 -0
  444. package/src/confidence/score.ts +243 -0
  445. package/src/confidence/types.ts +96 -0
  446. package/src/edge-path.ts +44 -0
  447. package/src/element-envelope.ts +76 -0
  448. package/src/factor/__tests__/validate.test.ts +98 -0
  449. package/src/factor/index.ts +8 -0
  450. package/src/factor/types.ts +41 -0
  451. package/src/factor/validate.ts +74 -0
  452. package/src/fgca/__tests__/chain-table.test.ts +172 -0
  453. package/src/fgca/__tests__/layout.test.ts +179 -0
  454. package/src/fgca/__tests__/parse-canonical.test.ts +248 -0
  455. package/src/fgca/__tests__/preview-layout.test.ts +124 -0
  456. package/src/fgca/__tests__/validate.test.ts +142 -0
  457. package/src/fgca/chain-table.ts +225 -0
  458. package/src/fgca/index.ts +45 -0
  459. package/src/fgca/layout.ts +204 -0
  460. package/src/fgca/nodeTypes.ts +11 -0
  461. package/src/fgca/nodes/FGCAActivityNode.tsx +65 -0
  462. package/src/fgca/nodes/FGCAChangeNode.tsx +64 -0
  463. package/src/fgca/nodes/FGCAFactorNode.tsx +64 -0
  464. package/src/fgca/nodes/FGCAGoalNode.tsx +72 -0
  465. package/src/fgca/parse-canonical.ts +400 -0
  466. package/src/fgca/preview-layout.ts +217 -0
  467. package/src/fgca/types.ts +50 -0
  468. package/src/fgca/validate.ts +126 -0
  469. package/src/geometry.ts +9 -0
  470. package/src/goals/__tests__/layout.test.ts +175 -0
  471. package/src/goals/__tests__/mutations.test.ts +111 -0
  472. package/src/goals/__tests__/parse-canonical.test.ts +145 -0
  473. package/src/goals/__tests__/validate.test.ts +202 -0
  474. package/src/goals/index.ts +21 -0
  475. package/src/goals/layout.ts +172 -0
  476. package/src/goals/mutations.ts +123 -0
  477. package/src/goals/parse-canonical.ts +286 -0
  478. package/src/goals/types.ts +85 -0
  479. package/src/goals/validate.ts +136 -0
  480. package/src/index.ts +23 -0
  481. package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -0
  482. package/src/process-blueprint/__tests__/layout.test.ts +195 -0
  483. package/src/process-blueprint/__tests__/validate.test.ts +310 -0
  484. package/src/process-blueprint/index.ts +31 -0
  485. package/src/process-blueprint/layout.ts +531 -0
  486. package/src/process-blueprint/types.ts +242 -0
  487. package/src/process-blueprint/validate.ts +181 -0
  488. package/src/process-map/__tests__/validate.test.ts +223 -0
  489. package/src/process-map/index.ts +10 -0
  490. package/src/process-map/types.ts +36 -0
  491. package/src/process-map/validate.ts +135 -0
  492. package/src/products/__tests__/validate.test.ts +239 -0
  493. package/src/products/index.ts +9 -0
  494. package/src/products/types.ts +31 -0
  495. package/src/products/validate.ts +112 -0
  496. package/src/repo-validate/__tests__/validate-repo.test.ts +149 -0
  497. package/src/repo-validate/index.ts +2 -0
  498. package/src/repo-validate/types.ts +50 -0
  499. package/src/repo-validate/validate-repo.ts +196 -0
  500. package/src/requirement/__tests__/example.test.ts +24 -0
  501. package/src/requirement/__tests__/validate.test.ts +96 -0
  502. package/src/requirement/index.ts +4 -0
  503. package/src/requirement/types.ts +35 -0
  504. package/src/requirement/validate.ts +92 -0
  505. package/src/scenarios/__tests__/validate.test.ts +209 -0
  506. package/src/scenarios/index.ts +15 -0
  507. package/src/scenarios/types.ts +37 -0
  508. package/src/scenarios/validate.ts +122 -0
  509. package/src/schema-version.ts +16 -0
  510. package/src/scope.ts +46 -0
  511. package/src/stakeholder/__tests__/validate.test.ts +101 -0
  512. package/src/stakeholder/index.ts +3 -0
  513. package/src/stakeholder/types.ts +33 -0
  514. package/src/stakeholder/validate.ts +63 -0
  515. package/src/target-state/__tests__/validate.test.ts +74 -0
  516. package/src/target-state/index.ts +2 -0
  517. package/src/target-state/types.ts +28 -0
  518. package/src/target-state/validate.ts +67 -0
  519. package/src/theme/index.ts +4 -0
  520. package/src/theme/themes.ts +237 -0
  521. package/src/theme/tokens.ts +133 -0
  522. package/src/typed-id.ts +56 -0
  523. package/src/validation-types.ts +36 -0
  524. package/src/webview/__tests__/entry-notations.test.ts +77 -0
  525. package/src/webview/__tests__/entry.test.ts +64 -0
  526. package/src/webview/__tests__/render-goals.test.ts +72 -0
  527. package/src/webview/entry.ts +292 -0
  528. package/src/webview/render-activities.ts +156 -0
  529. package/src/webview/render-activity-card.ts +234 -0
  530. package/src/webview/render-applications.ts +123 -0
  531. package/src/webview/render-blocks.ts +91 -0
  532. package/src/webview/render-capability-map.ts +98 -0
  533. package/src/webview/render-fgca.ts +122 -0
  534. package/src/webview/render-goals.ts +110 -0
  535. package/src/webview/render-process-blueprint.ts +207 -0
  536. package/src/webview/render-process-map.ts +93 -0
  537. package/src/webview/render-products.ts +91 -0
  538. package/src/webview/render-scenarios.ts +90 -0
  539. package/src/webview/render-util.ts +34 -0
  540. package/src/webview/styles.css +323 -0
  541. package/src/yaml-normalize.ts +56 -0
@@ -0,0 +1,56 @@
1
+ export { buildComplianceIndex } from './reverse-index.js';
2
+ export { buildLawTree, buildProductView } from './views.js';
3
+ export { buildGapReport } from './gap-report.js';
4
+ export type { GapReport, GapReportOptions } from './gap-report.js';
5
+ export { emptyCanon, ingestComplianceDoc } from './classify.js';
6
+ export type { ComplianceCanon, ComplianceProduct, ComplianceCodexDoc } from './classify.js';
7
+ export { renderComplianceMarkdown } from './markdown.js';
8
+ export type { ReportScope, MarkdownOptions } from './markdown.js';
9
+ export { renderComplianceHtml, renderImpactMatrixHtml } from './html.js';
10
+ export type { HtmlOptions, ImpactMatrixHtmlOptions } from './html.js';
11
+ export { buildImpactMatrix, renderImpactMarkdown, parseImpactViewConfig, COMPLIANCE_IMPACT_DEFAULTS, extractObjectDetails, computeDeadlineStatus } from './impact.js';
12
+ export type {
13
+ ImpactCell,
14
+ ImpactColumn,
15
+ ImpactEmptyCellLabels,
16
+ ImpactGrouping,
17
+ ImpactMatrix,
18
+ ImpactObligationFilter,
19
+ ImpactStatusDisplay,
20
+ ImpactSubjects,
21
+ ImpactViewConfig,
22
+ ParseImpactViewConfigResult,
23
+ } from './impact.js';
24
+ export {
25
+ assertionToScoringElement,
26
+ complianceConfidenceHeader,
27
+ requirementToScoringElement,
28
+ scoreComplianceView,
29
+ } from './confidence.js';
30
+ export {
31
+ parseCoverageMetricConfig,
32
+ buildCoverageMatrix,
33
+ } from './coverage-metric.js';
34
+ export type {
35
+ CoverageMetricConfig,
36
+ CoverageMetricScope,
37
+ CoverageMetricSubjects,
38
+ CoverageMetricThresholds,
39
+ CoverageMatrix,
40
+ CoverageRow,
41
+ ParseCoverageMetricResult,
42
+ RagStatus,
43
+ } from './coverage-metric.js';
44
+ export type {
45
+ ComplianceIndex,
46
+ ComplianceIndexInput,
47
+ DeadlineStatus,
48
+ IndexRequirement,
49
+ IndexAssertion,
50
+ LawTree,
51
+ LawTreeRequirement,
52
+ ProductView,
53
+ ProductRequirementStatus,
54
+ ObjectDetailDef,
55
+ ObjectDetailInput,
56
+ } from './types.js';
@@ -0,0 +1,135 @@
1
+ // Markdown renderers for the compliance views (vkgeorgia/strategy#84 Phase 5).
2
+ // Pure string builders consumed by the `transitrix export-compliance` CLI.
3
+ // PDF rendering lives in `html.ts` (HTML doc fed to WeasyPrint by the CLI).
4
+
5
+ import { buildComplianceMatrix } from '../compliance-matrix/index.js';
6
+ import { buildComplianceIndex } from './reverse-index.js';
7
+ import { buildLawTree, buildProductView } from './views.js';
8
+ import { buildGapReport } from './gap-report.js';
9
+ import type { ComplianceCanon } from './classify.js';
10
+ import type { AssertionStatus } from '../assertion/types.js';
11
+
12
+ const STATUS_LABELS: Record<AssertionStatus, string> = {
13
+ compliant: 'Compliant',
14
+ partial: 'Partial',
15
+ non_compliant: 'Non-compliant',
16
+ under_review: 'Under review',
17
+ n_a: 'N/A',
18
+ };
19
+
20
+ /** Escapes a value for a Markdown table cell (pipes + newlines). */
21
+ function cell(s: string): string {
22
+ return s.replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');
23
+ }
24
+
25
+ export type ReportScope =
26
+ | { mode: 'matrix' }
27
+ | { mode: 'law'; id: string }
28
+ | { mode: 'product'; id: string }
29
+ | { mode: 'gap' };
30
+
31
+ export interface MarkdownOptions {
32
+ /** Today as ISO YYYY-MM-DD — enables the gap dashboard's stale-assertion list. */
33
+ today?: string;
34
+ }
35
+
36
+ /** Renders the requested compliance view from a scanned canon to Markdown. */
37
+ export function renderComplianceMarkdown(canon: ComplianceCanon, scope: ReportScope, options: MarkdownOptions = {}): string {
38
+ switch (scope.mode) {
39
+ case 'matrix': return matrixMarkdown(canon);
40
+ case 'law': return lawMarkdown(canon, scope.id);
41
+ case 'product': return productMarkdown(canon, scope.id);
42
+ case 'gap': return gapMarkdown(canon, options.today);
43
+ }
44
+ }
45
+
46
+ function matrixMarkdown(canon: ComplianceCanon): string {
47
+ const m = buildComplianceMatrix({ products: canon.products, requirements: canon.requirements, assertions: canon.assertions });
48
+ const out: string[] = ['# Compliance Matrix', ''];
49
+ out.push(`_${m.summary.products} products × ${m.summary.requirements} requirements · ${m.summary.gaps} gaps · ${m.summary.assertions} assertions_`, '');
50
+ if (m.products.length === 0 || m.requirements.length === 0) {
51
+ out.push('_No products or requirements found in the scanned canon._', '');
52
+ return out.join('\n');
53
+ }
54
+ out.push(`| Product \\ Requirement | ${m.requirements.map(r => cell(r.name)).join(' | ')} |`);
55
+ out.push(`|---|${m.requirements.map(() => '---').join('|')}|`);
56
+ m.products.forEach((p, ri) => {
57
+ const cells = m.requirements.map((_r, ci) => {
58
+ const c = m.cells[ri][ci];
59
+ return c.status ? STATUS_LABELS[c.status] : '—';
60
+ });
61
+ const name = cell(p.name) + (p.unresolved ? ' ⚠' : '');
62
+ out.push(`| ${name} | ${cells.join(' | ')} |`);
63
+ });
64
+ out.push('');
65
+ return out.join('\n');
66
+ }
67
+
68
+ function lawMarkdown(canon: ComplianceCanon, lawId: string): string {
69
+ const index = buildComplianceIndex({ requirements: canon.requirements, assertions: canon.assertions });
70
+ const tree = buildLawTree(lawId, index);
71
+ const law = canon.codex.find(c => c.id === lawId);
72
+ const out: string[] = [`# Compliance — ${law ? law.name : lawId}`, ''];
73
+ out.push(`\`${lawId}\` · ${tree.requirements.length} requirement(s)`, '');
74
+ if (tree.requirements.length === 0) {
75
+ out.push(`_No requirements derive from \`${lawId}\`._`, '');
76
+ return out.join('\n');
77
+ }
78
+ for (const node of tree.requirements) {
79
+ const sev = node.requirement.severity ? ` — severity: ${node.requirement.severity}` : '';
80
+ out.push(`## ${node.requirement.name} (\`${node.requirement.id}\`)${sev}`, '');
81
+ if (node.assertions.length === 0) {
82
+ out.push('_No assertion — compliance gap._', '');
83
+ continue;
84
+ }
85
+ for (const a of node.assertions) {
86
+ const meta = [a.assessed_at ? `assessed ${a.assessed_at}` : null, a.next_review_at ? `review by ${a.next_review_at}` : null].filter(Boolean).join(', ');
87
+ out.push(`- **${STATUS_LABELS[a.status]}** — \`${a.id}\` (subject \`${a.subject}\`${meta ? `; ${meta}` : ''})`);
88
+ }
89
+ out.push('');
90
+ }
91
+ return out.join('\n');
92
+ }
93
+
94
+ function productMarkdown(canon: ComplianceCanon, productId: string): string {
95
+ const index = buildComplianceIndex({ requirements: canon.requirements, assertions: canon.assertions });
96
+ const view = buildProductView(productId, index);
97
+ const product = canon.products.find(p => p.id === productId);
98
+ const out: string[] = [`# Compliance — ${product ? product.name : productId}`, ''];
99
+ out.push(`\`${productId}\` · ${view.requirements.length} requirement(s) asserted`, '');
100
+ if (view.requirements.length === 0) {
101
+ out.push('_No assertion names this product as its subject._', '');
102
+ return out.join('\n');
103
+ }
104
+ out.push('| Requirement | Status | Assertion | Next review |', '|---|---|---|---|');
105
+ for (const { requirement, assertion } of view.requirements) {
106
+ out.push(`| ${cell(requirement.name)} (\`${requirement.id}\`) | ${STATUS_LABELS[assertion.status]} | \`${assertion.id}\` | ${assertion.next_review_at ?? '—'} |`);
107
+ }
108
+ out.push('');
109
+ return out.join('\n');
110
+ }
111
+
112
+ function gapMarkdown(canon: ComplianceCanon, today?: string): string {
113
+ const index = buildComplianceIndex({ requirements: canon.requirements, assertions: canon.assertions });
114
+ const report = buildGapReport(index, { today });
115
+ const total = report.requirementsWithoutAssertions.length + report.assertionsWithoutEvidence.length + report.staleAssertions.length + report.pastDeadlineRequirements.length;
116
+ const out: string[] = ['# Compliance Gap Dashboard', '', `_${total} gap(s) across 4 checks_`, ''];
117
+
118
+ out.push(`## Requirements without assertions (${report.requirementsWithoutAssertions.length})`, '');
119
+ if (report.requirementsWithoutAssertions.length === 0) out.push('_✓ none_', '');
120
+ else { for (const r of report.requirementsWithoutAssertions) out.push(`- [ ] \`${r.id}\` ${r.name}${r.severity ? ` — severity: ${r.severity}` : ''}${r.deadline ? ` — deadline: ${r.deadline}` : ''}`); out.push(''); }
121
+
122
+ out.push(`## Assertions without evidence — ASSERT-007 (${report.assertionsWithoutEvidence.length})`, '');
123
+ if (report.assertionsWithoutEvidence.length === 0) out.push('_✓ none_', '');
124
+ else { for (const a of report.assertionsWithoutEvidence) out.push(`- [ ] \`${a.id}\` — about \`${a.about}\`, subject \`${a.subject}\`, status ${a.status}`); out.push(''); }
125
+
126
+ out.push(`## Stale assertions — ASSERT-008 (${report.staleAssertions.length})`, '');
127
+ if (report.staleAssertions.length === 0) out.push('_✓ none_', '');
128
+ else { for (const a of report.staleAssertions) out.push(`- [ ] \`${a.id}\` — review due ${a.next_review_at ?? '—'}, subject \`${a.subject}\``); out.push(''); }
129
+
130
+ out.push(`## Past-deadline requirements — CV-5 (${report.pastDeadlineRequirements.length})`, '');
131
+ if (report.pastDeadlineRequirements.length === 0) out.push('_✓ none_', '');
132
+ else { for (const r of report.pastDeadlineRequirements) out.push(`- [ ] \`${r.id}\` ${r.name} — deadline: ${r.deadline ?? '—'}${r.severity ? `, severity: ${r.severity}` : ''}`); out.push(''); }
133
+
134
+ return out.join('\n');
135
+ }
@@ -0,0 +1,33 @@
1
+ // Reverse-index builder (vkgeorgia/strategy#84 Phase 3).
2
+
3
+ import type { ComplianceIndex, ComplianceIndexInput, IndexAssertion, IndexRequirement } from './types.js';
4
+
5
+ function push<K, V>(map: Map<K, V[]>, key: K, value: V): void {
6
+ const list = map.get(key);
7
+ if (list) list.push(value);
8
+ else map.set(key, [value]);
9
+ }
10
+
11
+ /**
12
+ * Builds the reverse indexes used by every compliance view. Pure; the input
13
+ * arrays are read, not mutated. Requirements with no `derived_from` simply do
14
+ * not appear under any law; assertions are indexed by both their requirement
15
+ * (`about`) and their subject.
16
+ */
17
+ export function buildComplianceIndex(input: ComplianceIndexInput): ComplianceIndex {
18
+ const requirementById = new Map<string, IndexRequirement>();
19
+ const requirementsByLaw = new Map<string, IndexRequirement[]>();
20
+ const assertionsByRequirement = new Map<string, IndexAssertion[]>();
21
+ const assertionsBySubject = new Map<string, IndexAssertion[]>();
22
+
23
+ for (const r of input.requirements) {
24
+ requirementById.set(r.id, r);
25
+ for (const law of r.derived_from ?? []) push(requirementsByLaw, law, r);
26
+ }
27
+ for (const a of input.assertions) {
28
+ push(assertionsByRequirement, a.about, a);
29
+ push(assertionsBySubject, a.subject, a);
30
+ }
31
+
32
+ return { requirementById, requirementsByLaw, assertionsByRequirement, assertionsBySubject };
33
+ }
@@ -0,0 +1,120 @@
1
+ // Shared compliance reverse-index + derived views (vkgeorgia/strategy#84
2
+ // Phase 3). The reverse-index pass (Law → Requirements, Requirement →
3
+ // Assertions, Subject → Assertions) backs the single-law tree and the
4
+ // single-product view here, and the gap dashboard in Phase 4.
5
+
6
+ import type { AssertionStatus } from '../assertion/types.js';
7
+
8
+ /** Projection of a REQUIREMENT the compliance views need. */
9
+ export interface IndexRequirement {
10
+ id: string;
11
+ name: string;
12
+ severity?: string;
13
+ /** Typed IDs of the codex sources this requirement derives from. */
14
+ derived_from?: string[];
15
+ /** Admission date (CONTRACT §6) — feeds DQ-1 freshness decay. */
16
+ admitted_at?: string;
17
+ /**
18
+ * Compliance deadline (ISO 8601 date, YYYY-MM-DD).
19
+ * When a gap exists on a cell whose requirement carries a deadline that is
20
+ * past or imminent, CV-3 renders an urgent decoration on the cell.
21
+ */
22
+ deadline?: string;
23
+ }
24
+
25
+ // ── Temporal status (CV-3) ──────────────────────────────────────────────────
26
+
27
+ /**
28
+ * Temporal status of a requirement deadline relative to today.
29
+ *
30
+ * - `past_due` — deadline has already passed (`deadline < today`).
31
+ * - `in_force` — deadline is within the next 30 days.
32
+ * - `upcoming` — deadline is more than 30 days away.
33
+ * - `none` — no deadline set.
34
+ */
35
+ export type DeadlineStatus = 'past_due' | 'in_force' | 'upcoming' | 'none';
36
+
37
+ /** Projection of an ASSERTION the compliance views need. */
38
+ export interface IndexAssertion {
39
+ id: string;
40
+ about: string;
41
+ subject: string;
42
+ status: AssertionStatus;
43
+ assessed_at?: string;
44
+ next_review_at?: string;
45
+ /** Number of evidence entries — feeds the Phase 4 "no evidence" gap. */
46
+ evidenceCount?: number;
47
+ /** Admission date (CONTRACT §6) — feeds DQ-1 freshness decay. */
48
+ admitted_at?: string;
49
+ /**
50
+ * Typed IDs of the stages / tasks where the requirement is realised for
51
+ * the subject (16-assertion.md §2 `realised_via`). Populated when the
52
+ * assertion carries granular evidence; absent when the claim covers the
53
+ * entire subject without stage decomposition. CV-3a uses this to fill
54
+ * stage-grouped matrix cells.
55
+ */
56
+ realised_via?: string[];
57
+ }
58
+
59
+ // ── Stage grouping (CV-3a) ──────────────────────────────────────────────────
60
+
61
+ /** One detail-level element of a business object, used as a matrix sub-column. */
62
+ export interface ObjectDetailDef {
63
+ id: string;
64
+ name: string;
65
+ }
66
+
67
+ /**
68
+ * Maps a business object to its ordered detail elements.
69
+ * Passed into `buildImpactMatrix` when `grouping.columns` is
70
+ * `object-details`. The details can be process stages, product
71
+ * components, capability modules, etc. — whatever sub-structure the object
72
+ * exposes. Typically extracted from a process-blueprint via`extractObjectDetails`.
73
+ */
74
+ export interface ObjectDetailInput {
75
+ objectId: string;
76
+ details: ObjectDetailDef[];
77
+ }
78
+
79
+ export interface ComplianceIndexInput {
80
+ requirements: IndexRequirement[];
81
+ assertions: IndexAssertion[];
82
+ }
83
+
84
+ /** The reverse-index — all maps are keyed by canonical id. */
85
+ export interface ComplianceIndex {
86
+ requirementById: Map<string, IndexRequirement>;
87
+ /** Codex artefact id → requirements whose `derived_from` names it. */
88
+ requirementsByLaw: Map<string, IndexRequirement[]>;
89
+ /** Requirement id → assertions whose `about` names it. */
90
+ assertionsByRequirement: Map<string, IndexAssertion[]>;
91
+ /** Subject id (product / process / capability) → assertions about it. */
92
+ assertionsBySubject: Map<string, IndexAssertion[]>;
93
+ }
94
+
95
+ // ── Single-law tree ─────────────────────────────────────────────────────────
96
+
97
+ export interface LawTreeRequirement {
98
+ requirement: IndexRequirement;
99
+ /** Assertions targeting this requirement, id-sorted. */
100
+ assertions: IndexAssertion[];
101
+ }
102
+ export interface LawTree {
103
+ lawId: string;
104
+ /** Requirements derived from the law, id-sorted. */
105
+ requirements: LawTreeRequirement[];
106
+ }
107
+
108
+ // ── Single-product view ─────────────────────────────────────────────────────
109
+
110
+ export interface ProductRequirementStatus {
111
+ /** The requirement the assertion is about. `name` falls back to the id when
112
+ * the requirement is not present in the scan (dangling `about`). */
113
+ requirement: IndexRequirement;
114
+ assertion: IndexAssertion;
115
+ }
116
+ export interface ProductView {
117
+ productId: string;
118
+ /** Requirements bound to the product via an assertion, requirement-id-sorted. */
119
+ requirements: ProductRequirementStatus[];
120
+ }
@@ -0,0 +1,46 @@
1
+ // Single-law tree + single-product view builders (vkgeorgia/strategy#84 Phase 3).
2
+
3
+ import type {
4
+ ComplianceIndex,
5
+ IndexRequirement,
6
+ LawTree,
7
+ ProductView,
8
+ } from './types.js';
9
+
10
+ function byId<T extends { id: string }>(a: T, b: T): number {
11
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
12
+ }
13
+
14
+ /**
15
+ * Law → Requirements → Assertions. Requirements are those whose `derived_from`
16
+ * names `lawId`; each carries the assertions targeting it. An unknown law (no
17
+ * requirement derives from it) yields an empty tree.
18
+ */
19
+ export function buildLawTree(lawId: string, index: ComplianceIndex): LawTree {
20
+ const requirements = [...(index.requirementsByLaw.get(lawId) ?? [])].sort(byId);
21
+ return {
22
+ lawId,
23
+ requirements: requirements.map(requirement => ({
24
+ requirement,
25
+ assertions: [...(index.assertionsByRequirement.get(requirement.id) ?? [])].sort(byId),
26
+ })),
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Product → the Requirements it has an assertion about, with each assertion's
32
+ * status. The requirement is resolved from the index; a dangling `about`
33
+ * (assertion references a requirement not in the scan) falls back to a stub
34
+ * carrying the id as its name, so the binding still shows.
35
+ */
36
+ export function buildProductView(productId: string, index: ComplianceIndex): ProductView {
37
+ const assertions = [...(index.assertionsBySubject.get(productId) ?? [])];
38
+ const requirements = assertions
39
+ .map(assertion => {
40
+ const requirement: IndexRequirement =
41
+ index.requirementById.get(assertion.about) ?? { id: assertion.about, name: assertion.about };
42
+ return { requirement, assertion };
43
+ })
44
+ .sort((a, b) => byId(a.requirement, b.requirement));
45
+ return { productId, requirements };
46
+ }
@@ -0,0 +1,200 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildComplianceMatrix, filterComplianceMatrix } from '../build.js';
3
+ import type { ComplianceMatrixInput } from '../types.js';
4
+
5
+ function input(over: Partial<ComplianceMatrixInput> = {}): ComplianceMatrixInput {
6
+ return {
7
+ products: [
8
+ { id: 'PRODUCT-ECOMM-1', name: 'E-Commerce' },
9
+ { id: 'PRODUCT-SUPPORT-1', name: 'Support' },
10
+ ],
11
+ requirements: [
12
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high' },
13
+ { id: 'REQUIREMENT-AUDIT-LOG-RETENTION-1', name: 'Audit logs', severity: 'medium' },
14
+ ],
15
+ assertions: [
16
+ { id: 'ASSERTION-1', about: 'REQUIREMENT-DATA-ERASURE-1', subject: 'PRODUCT-ECOMM-1', status: 'compliant' },
17
+ ],
18
+ ...over,
19
+ };
20
+ }
21
+
22
+ describe('buildComplianceMatrix', () => {
23
+ it('sorts products as rows and requirements as columns by id', () => {
24
+ const m = buildComplianceMatrix(input());
25
+ expect(m.products.map(p => p.id)).toEqual(['PRODUCT-ECOMM-1', 'PRODUCT-SUPPORT-1']);
26
+ expect(m.requirements.map(r => r.id)).toEqual([
27
+ 'REQUIREMENT-AUDIT-LOG-RETENTION-1',
28
+ 'REQUIREMENT-DATA-ERASURE-1',
29
+ ]);
30
+ });
31
+
32
+ it('places an assertion status in the (product, requirement) cell and gaps elsewhere', () => {
33
+ const m = buildComplianceMatrix(input());
34
+ // row 0 = ECOMM; col 1 = DATA-ERASURE (after the sort)
35
+ expect(m.cells[0][1]).toMatchObject({ status: 'compliant', assertionId: 'ASSERTION-1' });
36
+ expect(m.cells[0][0].status).toBeUndefined(); // ECOMM × AUDIT-LOG → gap
37
+ expect(m.cells[1][1].status).toBeUndefined(); // SUPPORT × DATA-ERASURE → gap
38
+ expect(m.summary).toMatchObject({ products: 2, requirements: 2, assertions: 1, gaps: 3 });
39
+ });
40
+
41
+ it('adds a product-typed assertion subject with no product file as an unresolved row', () => {
42
+ const m = buildComplianceMatrix(input({
43
+ assertions: [
44
+ { id: 'A1', about: 'REQUIREMENT-DATA-ERASURE-1', subject: 'PRODUCT-MOBILE-1', status: 'partial' },
45
+ ],
46
+ }));
47
+ const mobile = m.products.find(p => p.id === 'PRODUCT-MOBILE-1');
48
+ expect(mobile).toMatchObject({ unresolved: true });
49
+ const col = m.requirements.findIndex(r => r.id === 'REQUIREMENT-DATA-ERASURE-1');
50
+ const row = m.products.findIndex(p => p.id === 'PRODUCT-MOBILE-1');
51
+ expect(m.cells[row][col].status).toBe('partial');
52
+ });
53
+
54
+ it('ignores assertions whose subject is not a PRODUCT', () => {
55
+ const m = buildComplianceMatrix(input({
56
+ assertions: [
57
+ { id: 'A1', about: 'REQUIREMENT-DATA-ERASURE-1', subject: 'CAPABILITY-V2', status: 'compliant' },
58
+ { id: 'A2', about: 'REQUIREMENT-DATA-ERASURE-1', subject: 'PROCESS-X-1', status: 'partial' },
59
+ ],
60
+ }));
61
+ expect(m.summary.assertions).toBe(0);
62
+ expect(m.products.map(p => p.id)).toEqual(['PRODUCT-ECOMM-1', 'PRODUCT-SUPPORT-1']);
63
+ });
64
+ });
65
+
66
+ describe('buildComplianceMatrix — jurisdiction resolution (F16)', () => {
67
+ it('resolves Requirement.jurisdictions from derived_from → codex', () => {
68
+ const m = buildComplianceMatrix(input({
69
+ requirements: [
70
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high',
71
+ derived_from: ['LAW-PERSONAL-DATA-2017-1'] },
72
+ { id: 'REQUIREMENT-AUDIT-LOG-RETENTION-1', name: 'Audit logs', severity: 'medium',
73
+ derived_from: ['LAW-AUDIT-2020-1', 'LAW-PERSONAL-DATA-2017-1'] },
74
+ ],
75
+ codex: [
76
+ { id: 'LAW-PERSONAL-DATA-2017-1', jurisdiction: 'ge' },
77
+ { id: 'LAW-AUDIT-2020-1', jurisdiction: 'eu' },
78
+ ],
79
+ }));
80
+ const erasure = m.requirements.find(r => r.id === 'REQUIREMENT-DATA-ERASURE-1')!;
81
+ const audit = m.requirements.find(r => r.id === 'REQUIREMENT-AUDIT-LOG-RETENTION-1')!;
82
+ expect(erasure.jurisdictions).toEqual(['ge']);
83
+ // Sorted, deduplicated union.
84
+ expect(audit.jurisdictions).toEqual(['eu', 'ge']);
85
+ });
86
+
87
+ it('leaves jurisdictions undefined when no codex source resolves', () => {
88
+ const m = buildComplianceMatrix(input({
89
+ requirements: [
90
+ { id: 'REQUIREMENT-INTERNAL-1', name: 'Internal', severity: 'low' },
91
+ { id: 'REQUIREMENT-DANGLING-1', name: 'Dangling', severity: 'low',
92
+ derived_from: ['LAW-MISSING-1'] },
93
+ ],
94
+ codex: [{ id: 'LAW-OTHER-1', jurisdiction: 'us' }],
95
+ }));
96
+ expect(m.requirements.find(r => r.id === 'REQUIREMENT-INTERNAL-1')!.jurisdictions).toBeUndefined();
97
+ expect(m.requirements.find(r => r.id === 'REQUIREMENT-DANGLING-1')!.jurisdictions).toBeUndefined();
98
+ });
99
+
100
+ it('ignores codex entries with no jurisdiction (e.g. internal POLICY)', () => {
101
+ const m = buildComplianceMatrix(input({
102
+ requirements: [
103
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high',
104
+ derived_from: ['POLICY-INTERNAL-1'] },
105
+ ],
106
+ codex: [{ id: 'POLICY-INTERNAL-1' }],
107
+ }));
108
+ expect(m.requirements[0].jurisdictions).toBeUndefined();
109
+ });
110
+
111
+ it('works with no codex input (backwards-compatible)', () => {
112
+ const m = buildComplianceMatrix(input({
113
+ requirements: [
114
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high',
115
+ derived_from: ['LAW-PERSONAL-DATA-2017-1'] },
116
+ ],
117
+ }));
118
+ expect(m.requirements[0].jurisdictions).toBeUndefined();
119
+ });
120
+ });
121
+
122
+ describe('filterComplianceMatrix', () => {
123
+ it('trims requirement columns by severity', () => {
124
+ const m = buildComplianceMatrix(input());
125
+ const f = filterComplianceMatrix(m, { severities: ['high'] });
126
+ expect(f.requirements.map(r => r.id)).toEqual(['REQUIREMENT-DATA-ERASURE-1']);
127
+ expect(f.cells[0]).toHaveLength(1);
128
+ expect(f.cells[0][0]).toMatchObject({ status: 'compliant' });
129
+ });
130
+
131
+ it('blanks cells whose status is filtered out, preserving the grid shape', () => {
132
+ const m = buildComplianceMatrix(input());
133
+ const f = filterComplianceMatrix(m, { statuses: ['non_compliant'] });
134
+ // The compliant cell is now hidden (treated as a gap); columns unchanged.
135
+ expect(f.requirements).toHaveLength(2);
136
+ expect(f.cells[0][1].status).toBeUndefined();
137
+ expect(f.summary.assertions).toBe(0);
138
+ });
139
+
140
+ it('is a no-op when no filter dimension is set', () => {
141
+ const m = buildComplianceMatrix(input());
142
+ const f = filterComplianceMatrix(m, {});
143
+ expect(f.summary).toEqual(m.summary);
144
+ });
145
+
146
+ it('keeps only columns whose resolved jurisdiction is in the filter (F16)', () => {
147
+ const m = buildComplianceMatrix(input({
148
+ requirements: [
149
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high',
150
+ derived_from: ['LAW-PERSONAL-DATA-2017-1'] },
151
+ { id: 'REQUIREMENT-AUDIT-LOG-RETENTION-1', name: 'Audit logs', severity: 'medium',
152
+ derived_from: ['LAW-AUDIT-2020-1'] },
153
+ ],
154
+ codex: [
155
+ { id: 'LAW-PERSONAL-DATA-2017-1', jurisdiction: 'ge' },
156
+ { id: 'LAW-AUDIT-2020-1', jurisdiction: 'eu' },
157
+ ],
158
+ }));
159
+ const f = filterComplianceMatrix(m, { jurisdictions: ['ge'] });
160
+ expect(f.requirements.map(r => r.id)).toEqual(['REQUIREMENT-DATA-ERASURE-1']);
161
+ expect(f.cells[0]).toHaveLength(1);
162
+ });
163
+
164
+ it('drops requirements with no resolved jurisdiction when the filter is active', () => {
165
+ const m = buildComplianceMatrix(input({
166
+ requirements: [
167
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high',
168
+ derived_from: ['LAW-PERSONAL-DATA-2017-1'] },
169
+ { id: 'REQUIREMENT-INTERNAL-1', name: 'Internal', severity: 'low' },
170
+ ],
171
+ codex: [{ id: 'LAW-PERSONAL-DATA-2017-1', jurisdiction: 'ge' }],
172
+ }));
173
+ const f = filterComplianceMatrix(m, { jurisdictions: ['ge'] });
174
+ expect(f.requirements.map(r => r.id)).toEqual(['REQUIREMENT-DATA-ERASURE-1']);
175
+ });
176
+
177
+ it('combines jurisdiction filter with severity (intersection)', () => {
178
+ const m = buildComplianceMatrix(input({
179
+ requirements: [
180
+ { id: 'REQUIREMENT-DATA-ERASURE-1', name: 'Erasure', severity: 'high',
181
+ derived_from: ['LAW-PERSONAL-DATA-2017-1'] },
182
+ { id: 'REQUIREMENT-DATA-PORTABILITY-1', name: 'Portability', severity: 'medium',
183
+ derived_from: ['LAW-PERSONAL-DATA-2017-1'] },
184
+ ],
185
+ codex: [{ id: 'LAW-PERSONAL-DATA-2017-1', jurisdiction: 'ge' }],
186
+ }));
187
+ const f = filterComplianceMatrix(m, { jurisdictions: ['ge'], severities: ['high'] });
188
+ expect(f.requirements.map(r => r.id)).toEqual(['REQUIREMENT-DATA-ERASURE-1']);
189
+ });
190
+
191
+ it('empty jurisdiction array is treated as no-filter on that dimension', () => {
192
+ const m = buildComplianceMatrix(input({
193
+ requirements: [
194
+ { id: 'REQUIREMENT-INTERNAL-1', name: 'Internal', severity: 'low' },
195
+ ],
196
+ }));
197
+ const f = filterComplianceMatrix(m, { jurisdictions: [] });
198
+ expect(f.requirements).toHaveLength(1);
199
+ });
200
+ });
@@ -0,0 +1,57 @@
1
+ // Conformance test — the compliance matrix on the acme_corp worked examples
2
+ // (mirrored under tests/fixtures/notation-corpus/product, tests/fixtures/notation-corpus/requirement, tests/fixtures/notation-corpus/assertion).
3
+ // Pins the #84 Phase 2 acceptance: the matrix renders correctly and gaps are
4
+ // obvious.
5
+
6
+ import { describe, it, expect } from 'vitest';
7
+ import { readdirSync, readFileSync } from 'node:fs';
8
+ import { fileURLToPath } from 'node:url';
9
+ import path from 'node:path';
10
+ import yaml from 'js-yaml';
11
+ import { buildComplianceMatrix } from '../build.js';
12
+ import type { MatrixAssertionRef, MatrixProduct, MatrixRequirement } from '../types.js';
13
+
14
+ const examples = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../../tests/fixtures/notation-corpus');
15
+ function loadAll(dir: string): Record<string, unknown>[] {
16
+ const full = path.join(examples, dir);
17
+ return readdirSync(full)
18
+ .filter(f => f.endsWith('.yaml'))
19
+ .map(f => yaml.load(readFileSync(path.join(full, f), 'utf-8')) as Record<string, unknown>);
20
+ }
21
+
22
+ describe('compliance matrix — acme_corp worked examples', () => {
23
+ const products: MatrixProduct[] = loadAll('product').map(p => ({ id: String(p.id), name: String(p.name) }));
24
+ const requirements: MatrixRequirement[] = loadAll('requirement').map(r => ({
25
+ id: String(r.id), name: String(r.name), severity: r.severity as string | undefined,
26
+ }));
27
+ const assertions: MatrixAssertionRef[] = loadAll('assertion').map(a => ({
28
+ id: String(a.id), about: String(a.about), subject: String(a.subject),
29
+ status: a.status as MatrixAssertionRef['status'],
30
+ assessed_at: a.assessed_at as string | undefined,
31
+ next_review_at: a.next_review_at as string | undefined,
32
+ }));
33
+
34
+ const m = buildComplianceMatrix({ products, requirements, assertions });
35
+
36
+ it('rows = the two product files plus the dangling PRODUCT-MOBILE-1 subject', () => {
37
+ expect(m.products.map(p => p.id)).toEqual([
38
+ 'PRODUCT-ECOMM-1', 'PRODUCT-MOBILE-1', 'PRODUCT-SUPPORT-1',
39
+ ]);
40
+ expect(m.products.find(p => p.id === 'PRODUCT-MOBILE-1')?.unresolved).toBe(true);
41
+ });
42
+
43
+ it('columns = the two requirements', () => {
44
+ expect(m.requirements.map(r => r.id)).toEqual([
45
+ 'REQUIREMENT-AUDIT-LOG-RETENTION-1', 'REQUIREMENT-DATA-ERASURE-1',
46
+ ]);
47
+ });
48
+
49
+ it('the only product-subject assertion (mobile → data-erasure) is compliant; everything else is a gap', () => {
50
+ const row = m.products.findIndex(p => p.id === 'PRODUCT-MOBILE-1');
51
+ const col = m.requirements.findIndex(r => r.id === 'REQUIREMENT-DATA-ERASURE-1');
52
+ expect(m.cells[row][col]).toMatchObject({ status: 'compliant', assertionId: 'ASSERTION-MOBILE-DATA-ERASURE-1' });
53
+ // 3 products × 2 requirements = 6 cells; 1 filled → 5 gaps. The CRM
54
+ // (capability) and onboarding (process) assertions are not in the matrix.
55
+ expect(m.summary).toMatchObject({ products: 3, requirements: 2, assertions: 1, gaps: 5 });
56
+ });
57
+ });
Binary file
@@ -0,0 +1,11 @@
1
+ export { buildComplianceMatrix, filterComplianceMatrix } from './build.js';
2
+ export type {
3
+ ComplianceMatrix,
4
+ ComplianceMatrixInput,
5
+ MatrixProduct,
6
+ MatrixRequirement,
7
+ MatrixAssertionRef,
8
+ MatrixCell,
9
+ MatrixCodexDoc,
10
+ MatrixFilter,
11
+ } from './types.js';