@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,96 @@
1
+ // Confidence-scoring types per methodology CONTRACT §11 (Confidence and
2
+ // freshness). Two independent signals — source trust (authored, fixed) and
3
+ // freshness (derived, recomputed on read) — combined per element and rolled
4
+ // up to a view composite. See packages/diagrams/src/confidence/score.ts for
5
+ // the pure scoring functions.
6
+
7
+ /** Closed source-trust scale per CONTRACT §11.2. */
8
+ export type SourceQuality =
9
+ | 'authoritative'
10
+ | 'corroborated'
11
+ | 'single_source'
12
+ | 'unverified';
13
+
14
+ /** Confidence band per CONTRACT §11.6 — derived from a numeric confidence. */
15
+ export type ConfidenceBand = 'A' | 'B' | 'C' | 'D';
16
+
17
+ /** Per-TYPE freshness-decay parameters per CONTRACT §11.3. */
18
+ export interface DecayParams {
19
+ fresh_days: number;
20
+ stale_days: number;
21
+ floor: number;
22
+ }
23
+
24
+ /**
25
+ * Adopter-manifest `confidence_decay` block (MANIFEST.md §2). Both halves
26
+ * are optional: an absent `defaults` block falls back to the §11.3 implicit
27
+ * defaults, and an absent `by_type` entry inherits from `defaults`.
28
+ */
29
+ export interface ConfidenceDecayConfig {
30
+ defaults?: Partial<DecayParams>;
31
+ by_type?: Record<string, Partial<DecayParams>>;
32
+ }
33
+
34
+ /**
35
+ * One canonical element fed to the scorer. The caller (Studio / DSM) has
36
+ * already resolved `derived_from` to the field artefacts and extracted their
37
+ * `source_quality` labels — this module never reads files.
38
+ */
39
+ export interface ScoringElement {
40
+ /** Element TYPE name, used to look up per-TYPE decay (e.g. `CAPABILITY`). */
41
+ type: string;
42
+ /**
43
+ * ISO 8601 date the admission gate last ran for this element
44
+ * (`admitted_at`, CONTRACT §6). Reaffirmation bumps this date — the cure
45
+ * for staleness. Absent ⇒ treated as fully stale (freshness = floor).
46
+ */
47
+ admitted_at?: string;
48
+ /**
49
+ * Source qualities resolved from `derived_from` — one entry per cited
50
+ * field artefact. Undefined or empty ⇒ unsourced: scored as `unverified`
51
+ * (0.25) and counted separately per §11.5.
52
+ */
53
+ sources?: SourceQuality[];
54
+ }
55
+
56
+ /** Per-element scoring output. */
57
+ export interface ElementScore {
58
+ /** Max source-trust weight over `sources`; 0.25 (`unverified`) if unsourced. */
59
+ source_trust: number;
60
+ /** Freshness in [floor, 1.0] per the §11.3 curve. */
61
+ freshness: number;
62
+ /** `source_trust × freshness`. */
63
+ confidence: number;
64
+ /**
65
+ * True iff at least one resolvable `derived_from` source was supplied.
66
+ * Drives the §11.5 "counted separately" gap signal and view coverage.
67
+ */
68
+ sourced: boolean;
69
+ }
70
+
71
+ /**
72
+ * View-level composite per CONTRACT §11.6. Three numbers surfaced alongside
73
+ * the view's formation date; the headline `band` is the band of the
74
+ * weakest link.
75
+ */
76
+ export interface ViewComposite {
77
+ /** `min(confidence)` over the rendered elements. The headline figure. */
78
+ weakest_link: number;
79
+ /** Arithmetic mean of `confidence` (equal element weight in v1). */
80
+ mean: number;
81
+ /** Fraction of elements with `sourced === true`. */
82
+ coverage: number;
83
+ /** Band of the weakest link. */
84
+ band: ConfidenceBand;
85
+ element_count: number;
86
+ /** Elements with no resolvable `derived_from` — `unsourced_count` / `element_count` is the gap. */
87
+ unsourced_count: number;
88
+ }
89
+
90
+ /** Full scorer output: per-element + composite, plus the `today` used. */
91
+ export interface ViewScore {
92
+ elements: ElementScore[];
93
+ composite: ViewComposite;
94
+ /** The date used as `today` (the reference for `age_days`). */
95
+ today: string;
96
+ }
@@ -0,0 +1,44 @@
1
+ // Shared edge geometry for the static notation previews (Goals, FGCA, FGA,
2
+ // Activities). All four render dependency/relationship edges as a single cubic
3
+ // Bézier with horizontal control handles: each control point shares its
4
+ // endpoint's Y, so the tangent is horizontal at both ends and the marker-end
5
+ // arrow reads as perpendicular to the node's vertical edge.
6
+ //
7
+ // Pulling the path math here (rather than duplicating it inline in each
8
+ // preview) makes the configurable-curvature behaviour (vkgeorgia/strategy#76)
9
+ // unit-testable — the extension has no test harness.
10
+
11
+ /**
12
+ * Base handle length floor + span factors. The handle grows with both the
13
+ * horizontal and vertical span so the curve stays visibly horizontal long
14
+ * enough for the arrowhead to sit flush against the line.
15
+ */
16
+ export const EDGE_MIN_HANDLE = 64;
17
+ const DX_FACTOR = 0.5;
18
+ const DY_FACTOR = 0.8;
19
+
20
+ /** Multiplier applied to the base handle length. 1 = historical appearance. */
21
+ export const DEFAULT_EDGE_CURVATURE = 1;
22
+
23
+ /**
24
+ * Builds the SVG `d` for a horizontal-tangent cubic Bézier from (sx,sy) to
25
+ * (tx,ty).
26
+ *
27
+ * `curvature` scales the control-handle length:
28
+ * - 0 → control points collapse onto the endpoints ⇒ a straight line.
29
+ * - 1 → the historical curve (no visual change from before #76).
30
+ * - >1 → progressively stronger arc.
31
+ */
32
+ export function horizontalCubicEdgePath(
33
+ sx: number,
34
+ sy: number,
35
+ tx: number,
36
+ ty: number,
37
+ curvature: number = DEFAULT_EDGE_CURVATURE,
38
+ ): string {
39
+ const dx = tx - sx;
40
+ const dy = ty - sy;
41
+ const baseHandle = Math.max(EDGE_MIN_HANDLE, Math.abs(dx) * DX_FACTOR, Math.abs(dy) * DY_FACTOR);
42
+ const handle = baseHandle * curvature;
43
+ return `M${sx},${sy} C${sx + handle},${sy} ${tx - handle},${ty} ${tx},${ty}`;
44
+ }
@@ -0,0 +1,76 @@
1
+ // Shared §3 envelope validator for standalone element primitives.
2
+ //
3
+ // Every standalone element file in the methodology canon carries the same
4
+ // envelope: a fixed `notation` tag, a canonical `id` whose TYPE prefix matches
5
+ // the element TYPE, `name`, an admission record (`zone`/`admitted_at`/
6
+ // `admitted_by`/`gate_checks`), and a primitive lifecycle
7
+ // (`valid_from`/`valid_to`). Per-TYPE fields (§7) sit between.
8
+ //
9
+ // Each per-TYPE validator delegates envelope checks here so the §3 rule lives
10
+ // in one place; per-TYPE fields (subtype enums, cross-references) are checked
11
+ // in the TYPE's own validator. The error `code` is parameterised so an
12
+ // envelope failure surfaces under the TYPE's own code (e.g. `FACTOR-001`,
13
+ // `CHANGE-001`), preserving per-TYPE attribution.
14
+
15
+ import type { ValidationError } from './validation-types.js';
16
+ import { isCanonicalIdOfType } from './typed-id.js';
17
+
18
+ export interface EnvelopeOptions {
19
+ /** Fixed `notation:` tag — lowercased TYPE short name (e.g. `factor`). */
20
+ notation: string;
21
+ /** Required `id:` TYPE prefix (e.g. `FACTOR`). */
22
+ idType: string;
23
+ /** Error code used for every envelope failure (e.g. `FACTOR-001`). */
24
+ code: string;
25
+ }
26
+
27
+ export interface EnvelopeResult {
28
+ /** The input narrowed to a record on success; `null` when the input is not a mapping. */
29
+ record: Record<string, unknown> | null;
30
+ errors: ValidationError[];
31
+ }
32
+
33
+ export function validateElementEnvelope(input: unknown, opts: EnvelopeOptions): EnvelopeResult {
34
+ const errors: ValidationError[] = [];
35
+
36
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
37
+ errors.push({ code: opts.code, message: `${opts.idType} must be a YAML mapping.` });
38
+ return { record: null, errors };
39
+ }
40
+ const r = input as Record<string, unknown>;
41
+
42
+ if (r.notation !== opts.notation) {
43
+ errors.push({
44
+ code: opts.code,
45
+ message: `notation must be the fixed value "${opts.notation}".`,
46
+ path: 'notation',
47
+ });
48
+ }
49
+ if (!isCanonicalIdOfType(r.id, opts.idType)) {
50
+ errors.push({
51
+ code: opts.code,
52
+ message: `id "${String(r.id)}" must match ${opts.idType}-[<middle>-]<INTEGER>.`,
53
+ path: 'id',
54
+ });
55
+ }
56
+ for (const f of ['name', 'admitted_at', 'admitted_by', 'valid_from'] as const) {
57
+ if (typeof r[f] !== 'string' || (r[f] as string).trim() === '') {
58
+ errors.push({ code: opts.code, message: `${f} is required.`, path: f });
59
+ }
60
+ }
61
+ if (r.zone !== 'canon') {
62
+ errors.push({ code: opts.code, message: 'zone is required and must be "canon".', path: 'zone' });
63
+ }
64
+ if (r.gate_checks === null || typeof r.gate_checks !== 'object' || Array.isArray(r.gate_checks)) {
65
+ errors.push({ code: opts.code, message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
66
+ }
67
+ if (!('valid_to' in r) || !(typeof r.valid_to === 'string' || r.valid_to === null)) {
68
+ errors.push({
69
+ code: opts.code,
70
+ message: 'valid_to is required (an ISO date string or null).',
71
+ path: 'valid_to',
72
+ });
73
+ }
74
+
75
+ return { record: r, errors };
76
+ }
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateFactor } from '../validate.js';
3
+
4
+ function valid(): Record<string, unknown> {
5
+ return {
6
+ notation: 'factor',
7
+ id: 'FACTOR-EU-REG-1',
8
+ name: 'EU regulatory window for market entry',
9
+ type: 'external',
10
+ category: 'legal',
11
+ description: 'Standing external driver — the EU regulatory regime.',
12
+ references_constraint: ['CONSTRAINT-GDPR-RESIDENCY-1'],
13
+ zone: 'canon',
14
+ admitted_at: '2026-05-29',
15
+ admitted_by: 'v.korobeinikov',
16
+ gate_checks: { uniqueness: 'pass', consistency: 'pass', completeness: 'pass' },
17
+ valid_from: '2026-05-26',
18
+ valid_to: null,
19
+ };
20
+ }
21
+
22
+ const codes = (input: unknown): string[] => validateFactor(input).errors.map(e => e.code);
23
+ const warns = (input: unknown): string[] => validateFactor(input).warnings.map(w => w.code);
24
+
25
+ describe('validateFactor — positive', () => {
26
+ it('accepts the worked-example FACTOR-EU-REG-1', () => {
27
+ const r = validateFactor(valid());
28
+ expect(r.valid, JSON.stringify(r.errors)).toBe(true);
29
+ expect(r.errors).toHaveLength(0);
30
+ });
31
+
32
+ it('accepts a minimal factor (no type/category/references)', () => {
33
+ const r = valid();
34
+ delete r.type;
35
+ delete r.category;
36
+ delete r.references_constraint;
37
+ expect(validateFactor(r).valid).toBe(true);
38
+ });
39
+ });
40
+
41
+ describe('validateFactor — FACTOR-001 (envelope / shape)', () => {
42
+ it('flags a non-object', () => {
43
+ expect(codes(null)).toEqual(['FACTOR-001']);
44
+ expect(codes(['x'])).toEqual(['FACTOR-001']);
45
+ });
46
+
47
+ it('flags a wrong notation tag', () => {
48
+ expect(codes({ ...valid(), notation: 'driver' })).toContain('FACTOR-001');
49
+ });
50
+
51
+ it('flags an id with the wrong TYPE prefix', () => {
52
+ expect(codes({ ...valid(), id: 'GOAL-EU-1' })).toContain('FACTOR-001');
53
+ });
54
+
55
+ it('flags an id with a leading-zero terminal', () => {
56
+ expect(codes({ ...valid(), id: 'FACTOR-EU-REG-01' })).toContain('FACTOR-001');
57
+ });
58
+
59
+ it('flags a missing valid_to key (distinct from a null value)', () => {
60
+ const r = valid();
61
+ delete r.valid_to;
62
+ expect(codes(r)).toContain('FACTOR-001');
63
+ expect(validateFactor({ ...valid(), valid_to: null }).valid).toBe(true);
64
+ });
65
+
66
+ it('flags references_constraint entries that are not CONSTRAINT typed ids', () => {
67
+ expect(codes({ ...valid(), references_constraint: ['GOAL-EU-1'] })).toContain('FACTOR-001');
68
+ expect(codes({ ...valid(), references_constraint: 'CONSTRAINT-X-1' })).toContain('FACTOR-001');
69
+ });
70
+ });
71
+
72
+ describe('validateFactor — FACTOR-002 (type enum)', () => {
73
+ it('flags a type outside external/internal', () => {
74
+ expect(codes({ ...valid(), type: 'driver' })).toContain('FACTOR-002');
75
+ });
76
+
77
+ it('accepts each permitted type', () => {
78
+ for (const t of ['external', 'internal']) {
79
+ expect(codes({ ...valid(), type: t, category: undefined })).not.toContain('FACTOR-002');
80
+ }
81
+ });
82
+ });
83
+
84
+ describe('validateFactor — FACTOR-003 (PESTLE category)', () => {
85
+ it('flags a category outside the PESTLE classes', () => {
86
+ expect(codes({ ...valid(), category: 'cultural' })).toContain('FACTOR-003');
87
+ });
88
+
89
+ it('warns when category is set on an internal factor', () => {
90
+ expect(warns({ ...valid(), type: 'internal', category: 'economic' })).toContain('FACTOR-003');
91
+ });
92
+
93
+ it('accepts each permitted PESTLE class', () => {
94
+ for (const c of ['political', 'economic', 'social', 'technological', 'legal', 'environmental']) {
95
+ expect(codes({ ...valid(), category: c })).not.toContain('FACTOR-003');
96
+ }
97
+ });
98
+ });
@@ -0,0 +1,8 @@
1
+ // The `Factor` type is re-exported under the alias `FactorPrimitive` at the
2
+ // package surface to avoid a name collision with the legacy FGCA-inline
3
+ // `Factor` shape exported from `./goals/index` (a v0.x view shape with
4
+ // numeric ids — distinct from this element primitive). Both types remain
5
+ // importable from their module subpaths.
6
+ export type { Factor as FactorPrimitive, FactorType, FactorCategory } from './types.js';
7
+ export { FACTOR_TYPES, FACTOR_CATEGORIES } from './types.js';
8
+ export { validateFactor } from './validate.js';
@@ -0,0 +1,41 @@
1
+ // FACTOR — motivation-layer driver primitive.
2
+ // Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.1 + envelope §3.
3
+
4
+ import type { GateChecks } from '../requirement/types.js';
5
+
6
+ /** Optional subtype — internal/external organisation force. */
7
+ export type FactorType = 'external' | 'internal';
8
+
9
+ export const FACTOR_TYPES = ['external', 'internal'] as const;
10
+
11
+ /** PESTLE sub-classification — external factors only. Open-ended in practice
12
+ * but v1 fixes the six standard classes; an unknown category is flagged. */
13
+ export type FactorCategory =
14
+ | 'political'
15
+ | 'economic'
16
+ | 'social'
17
+ | 'technological'
18
+ | 'legal'
19
+ | 'environmental';
20
+
21
+ export const FACTOR_CATEGORIES = [
22
+ 'political', 'economic', 'social', 'technological', 'legal', 'environmental',
23
+ ] as const;
24
+
25
+ export interface Factor {
26
+ notation: 'factor';
27
+ id: string;
28
+ name: string;
29
+ type?: FactorType;
30
+ category?: FactorCategory;
31
+ description?: string;
32
+ references_constraint?: string[];
33
+
34
+ zone: 'canon';
35
+ admitted_at: string;
36
+ admitted_by: string;
37
+ gate_checks: GateChecks;
38
+
39
+ valid_from: string;
40
+ valid_to: string | null;
41
+ }
@@ -0,0 +1,74 @@
1
+ // FACTOR validator — methodology notations/ELEMENT_PRIMITIVES.md §7.1.
2
+ //
3
+ // Implements FACTOR-001..003. Cross-cutting HDR-/LIFECYCLE-/policy rules
4
+ // (CONTRACT.md §8) are owned elsewhere and out of scope for this
5
+ // single-artefact validator.
6
+
7
+ import type { ValidationError, ValidationResult, ValidationWarning } from '../validation-types.js';
8
+ import { typeOfId } from '../typed-id.js';
9
+ import { validateElementEnvelope } from '../element-envelope.js';
10
+ import { FACTOR_CATEGORIES, FACTOR_TYPES } from './types.js';
11
+
12
+ export function validateFactor(input: unknown): ValidationResult {
13
+ const errors: ValidationError[] = [];
14
+ const warnings: ValidationWarning[] = [];
15
+
16
+ const { record, errors: envErrors } = validateElementEnvelope(input, {
17
+ notation: 'factor',
18
+ idType: 'FACTOR',
19
+ code: 'FACTOR-001',
20
+ });
21
+ errors.push(...envErrors);
22
+ if (!record) return { valid: false, errors, warnings };
23
+
24
+ // FACTOR-002 — type subtype enum (optional field).
25
+ if (record.type !== undefined && !FACTOR_TYPES.includes(record.type as never)) {
26
+ errors.push({
27
+ code: 'FACTOR-002',
28
+ message: `type "${String(record.type)}" must be one of ${FACTOR_TYPES.join(', ')}.`,
29
+ path: 'type',
30
+ });
31
+ }
32
+
33
+ // FACTOR-003 — PESTLE category enum on external factors; warn on internal.
34
+ if (record.category !== undefined) {
35
+ if (!FACTOR_CATEGORIES.includes(record.category as never)) {
36
+ errors.push({
37
+ code: 'FACTOR-003',
38
+ message: `category "${String(record.category)}" must be a PESTLE class (${FACTOR_CATEGORIES.join(', ')}).`,
39
+ path: 'category',
40
+ });
41
+ } else if (record.type === 'internal') {
42
+ // §7.1: "Omit on internal factors — PESTLE does not apply."
43
+ warnings.push({
44
+ code: 'FACTOR-003',
45
+ message: 'category is set on an internal factor; PESTLE applies to external drivers only.',
46
+ path: 'category',
47
+ });
48
+ }
49
+ }
50
+
51
+ // FACTOR-001 — references_constraint shape + TYPE on each entry.
52
+ if (record.references_constraint !== undefined) {
53
+ if (!Array.isArray(record.references_constraint)) {
54
+ errors.push({
55
+ code: 'FACTOR-001',
56
+ message: 'references_constraint must be a list of typed CONSTRAINT IDs.',
57
+ path: 'references_constraint',
58
+ });
59
+ } else {
60
+ record.references_constraint.forEach((ref, i) => {
61
+ const type = typeOfId(ref);
62
+ if (type !== 'CONSTRAINT') {
63
+ errors.push({
64
+ code: 'FACTOR-001',
65
+ message: `references_constraint[${i}] "${String(ref)}" must be a CONSTRAINT typed ID.`,
66
+ path: `references_constraint[${i}]`,
67
+ });
68
+ }
69
+ });
70
+ }
71
+ }
72
+
73
+ return { valid: errors.length === 0, errors, warnings };
74
+ }
@@ -0,0 +1,172 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildChainTable, type ChainTable, type ChainColumn } from '../chain-table.js';
3
+ import type { FGCAPreviewDoc } from '../preview-layout.js';
4
+
5
+ // Renders a ChainTable to a compact text grid for readable assertions. Each
6
+ // cell shows "label×rowSpan" (×1 omitted); a position covered by a span above
7
+ // shows "·".
8
+ function asGrid(t: ChainTable): string[][] {
9
+ return t.rows.map(row =>
10
+ row.map(c => {
11
+ if (c === null) return '·';
12
+ const label = c.cell ? c.cell.label : '∅';
13
+ return c.rowSpan > 1 ? `${label}×${c.rowSpan}` : label;
14
+ }),
15
+ );
16
+ }
17
+
18
+ describe('buildChainTable — worked example (FGCA)', () => {
19
+ // F1 → G1, G2 ; G1 → C1 → A1 ; G2 → C2 → A2, A3
20
+ const doc: FGCAPreviewDoc = {
21
+ factors: [{ id: 1, name: 'F1' }],
22
+ goals: [
23
+ { id: 10, name: 'G1', factor: [{ id: 1 }] },
24
+ { id: 11, name: 'G2', factor: [{ id: 1 }] },
25
+ ],
26
+ changes: [
27
+ { id: 20, name: 'C1', goal_id: 10, activity_ids: [30] },
28
+ { id: 21, name: 'C2', goal_id: 11, activity_ids: [31, 32] },
29
+ ],
30
+ activities: [
31
+ { id: 30, name: 'A1', goal_id: 10 },
32
+ { id: 31, name: 'A2', goal_id: 11 },
33
+ { id: 32, name: 'A3', goal_id: 11 },
34
+ ],
35
+ };
36
+
37
+ it('produces the spec grid with F1 spanning 3 and G2/C2 spanning 2', () => {
38
+ const t = buildChainTable(doc);
39
+ expect(t.columns).toEqual<ChainColumn[]>(['factor', 'goal', 'change', 'activity']);
40
+ expect(asGrid(t)).toEqual([
41
+ ['F1×3', 'G1', 'C1', 'A1'],
42
+ ['·', 'G2×2', 'C2×2', 'A2'],
43
+ ['·', '·', '·', 'A3'],
44
+ ]);
45
+ });
46
+
47
+ it('orders the merged cells with correct rowSpans on the model', () => {
48
+ const t = buildChainTable(doc);
49
+ // Factor cell spans all three rows.
50
+ expect(t.rows[0][0]).toMatchObject({ rowSpan: 3, cell: { label: 'F1' } });
51
+ // Covered positions are null (no <td> emitted).
52
+ expect(t.rows[1][0]).toBeNull();
53
+ expect(t.rows[2][1]).toBeNull();
54
+ });
55
+ });
56
+
57
+ describe('buildChainTable — FGA (no Change column)', () => {
58
+ // FGA links Goal → Activity directly via activity.goal_id; no changes.
59
+ const doc: FGCAPreviewDoc = {
60
+ factors: [{ id: 1, name: 'F1' }],
61
+ goals: [{ id: 10, name: 'G1', factor: [{ id: 1 }] }],
62
+ activities: [
63
+ { id: 30, name: 'A1', goal_id: 10 },
64
+ { id: 31, name: 'A2', goal_id: 10 },
65
+ ],
66
+ };
67
+
68
+ it('emits three columns and merges Factor/Goal across the two activities', () => {
69
+ const t = buildChainTable(doc, { hideChanges: true });
70
+ expect(t.columns).toEqual<ChainColumn[]>(['factor', 'goal', 'activity']);
71
+ expect(asGrid(t)).toEqual([
72
+ ['F1×2', 'G1×2', 'A1'],
73
+ ['·', '·', 'A2'],
74
+ ]);
75
+ });
76
+ });
77
+
78
+ describe('buildChainTable — missing downstream links (gaps stay visible)', () => {
79
+ it('shows a factor with no goal, a goal with no change, and a change with no activity', () => {
80
+ const doc: FGCAPreviewDoc = {
81
+ factors: [
82
+ { id: 1, name: 'F1' },
83
+ { id: 2, name: 'F2' }, // no goals
84
+ ],
85
+ goals: [
86
+ { id: 10, name: 'G1', factor: [{ id: 1 }] }, // no change, no activity
87
+ { id: 11, name: 'G2', factor: [{ id: 1 }] }, // has a change with no activity
88
+ ],
89
+ changes: [{ id: 20, name: 'C1', goal_id: 11, activity_ids: [] }],
90
+ activities: [],
91
+ };
92
+ const t = buildChainTable(doc);
93
+ expect(asGrid(t)).toEqual([
94
+ ['F1×2', 'G1', '∅', '∅'],
95
+ ['·', 'G2', 'C1', '∅'],
96
+ ['F2', '∅', '∅', '∅'],
97
+ ]);
98
+ });
99
+
100
+ it('renders a change-less direct goal→activity path with an empty Change cell', () => {
101
+ const doc: FGCAPreviewDoc = {
102
+ factors: [{ id: 1, name: 'F1' }],
103
+ goals: [{ id: 10, name: 'G1', factor: [{ id: 1 }] }],
104
+ // activity bound straight to the goal, not covered by any change
105
+ changes: [],
106
+ activities: [{ id: 30, name: 'A1', goal_id: 10 }],
107
+ };
108
+ const t = buildChainTable(doc);
109
+ expect(asGrid(t)).toEqual([['F1', 'G1', '∅', 'A1']]);
110
+ });
111
+ });
112
+
113
+ describe('buildChainTable — orphans (broken refs are warnings, not errors)', () => {
114
+ it('places a goal with a missing factor in a trailing empty-Factor row', () => {
115
+ const doc: FGCAPreviewDoc = {
116
+ factors: [{ id: 1, name: 'F1' }],
117
+ goals: [
118
+ { id: 10, name: 'G1', factor: [{ id: 1 }] },
119
+ { id: 11, name: 'Gx', factor: [{ id: 99 }] }, // factor 99 does not exist
120
+ { id: 12, name: 'Gy' }, // no factor at all
121
+ ],
122
+ changes: [{ id: 20, name: 'C1', goal_id: 10, activity_ids: [30] }],
123
+ activities: [{ id: 30, name: 'A1', goal_id: 10 }],
124
+ };
125
+ const t = buildChainTable(doc);
126
+ expect(asGrid(t)).toEqual([
127
+ ['F1', 'G1', 'C1', 'A1'],
128
+ ['∅×2', 'Gx', '∅', '∅'],
129
+ ['·', 'Gy', '∅', '∅'],
130
+ ]);
131
+ });
132
+
133
+ it('surfaces an unlinked activity as a trailing row with empty cells to its left', () => {
134
+ const doc: FGCAPreviewDoc = {
135
+ factors: [{ id: 1, name: 'F1' }],
136
+ goals: [{ id: 10, name: 'G1', factor: [{ id: 1 }] }],
137
+ changes: [{ id: 20, name: 'C1', goal_id: 10, activity_ids: [30] }],
138
+ activities: [
139
+ { id: 30, name: 'A1', goal_id: 10 },
140
+ { id: 99, name: 'Aorphan' }, // no goal, no change
141
+ ],
142
+ };
143
+ const t = buildChainTable(doc);
144
+ expect(asGrid(t)).toEqual([
145
+ ['F1', 'G1', 'C1', 'A1'],
146
+ ['∅', '∅', '∅', 'Aorphan'],
147
+ ]);
148
+ });
149
+
150
+ it('surfaces a change whose goal is missing as an empty Factor+Goal row', () => {
151
+ const doc: FGCAPreviewDoc = {
152
+ factors: [],
153
+ goals: [],
154
+ changes: [{ id: 20, name: 'Cx', goal_id: 999, activity_ids: [30] }],
155
+ activities: [{ id: 30, name: 'A1' }],
156
+ };
157
+ const t = buildChainTable(doc);
158
+ expect(asGrid(t)).toEqual([['∅', '∅', 'Cx', 'A1']]);
159
+ });
160
+ });
161
+
162
+ describe('buildChainTable — name fallback', () => {
163
+ it('falls back to the id when an element has an empty name', () => {
164
+ const doc: FGCAPreviewDoc = {
165
+ factors: [{ id: 7, name: '' }],
166
+ goals: [],
167
+ activities: [],
168
+ };
169
+ const t = buildChainTable(doc);
170
+ expect(t.rows[0][0]?.cell?.label).toBe('7');
171
+ });
172
+ });