@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,531 @@
1
+ import type {
2
+ AspectCategory,
3
+ AspectEntry,
4
+ AspectPill,
5
+ AspectRow,
6
+ ComplianceChip,
7
+ ComplianceDecoration,
8
+ ComplianceLaneAssertion,
9
+ ComplianceLaneInput,
10
+ ComplianceLaneRequirement,
11
+ ComplianceRow,
12
+ ProcessBlueprintLayoutOptions,
13
+ LegendCell,
14
+ ProcessBlueprintFile,
15
+ ProcessBlueprintLayout,
16
+ Stage,
17
+ StageHeaderCell,
18
+ StageTextCell,
19
+ } from './types.js';
20
+
21
+ const ASPECT_CATEGORIES: AspectCategory[] = ['systems', 'actors', 'equipment', 'information_entities'];
22
+
23
+ const ASPECT_LABEL: Record<AspectCategory, string> = {
24
+ systems: 'Systems',
25
+ actors: 'Actors',
26
+ equipment: 'Equipment',
27
+ information_entities: 'Information',
28
+ };
29
+
30
+ // The compliance lane is opt-in, so its two options have no meaningful default
31
+ // (absent = lane disabled). Every other option is a sizing value that always
32
+ // resolves to a number — keep those `Required`, but exclude the compliance pair
33
+ // rather than forcing them to a non-optional type they can't satisfy.
34
+ type SizingOptionKeys = Exclude<
35
+ keyof ProcessBlueprintLayoutOptions,
36
+ 'complianceLane' | 'complianceInput'
37
+ >;
38
+
39
+ /**
40
+ * Options after defaults are applied: every sizing field is guaranteed present;
41
+ * the compliance lane fields stay optional (undefined = lane disabled).
42
+ */
43
+ type ResolvedLayoutOptions = Required<Pick<ProcessBlueprintLayoutOptions, SizingOptionKeys>> &
44
+ Pick<ProcessBlueprintLayoutOptions, 'complianceLane' | 'complianceInput'>;
45
+
46
+ const DEFAULTS = {
47
+ legendColumnWidth: 140,
48
+ stageColumnWidth: 220,
49
+ stageHeaderHeight: 40,
50
+ goalRowHeight: 56,
51
+ resultRowHeight: 56,
52
+ aspectRowMinHeight: 60,
53
+ pillHeight: 28,
54
+ pillGap: 4,
55
+ cellPadding: 8,
56
+ textLineHeight: 15,
57
+ textCharWidth: 6.2,
58
+ cellTextPadX: 10,
59
+ cellTextPadY: 10,
60
+ maxTextLines: 6,
61
+ } satisfies Required<Pick<ProcessBlueprintLayoutOptions, SizingOptionKeys>>;
62
+
63
+ interface RawPill {
64
+ category: AspectCategory;
65
+ entryIndex: number;
66
+ name: string;
67
+ id?: string;
68
+ startStageIndex: number;
69
+ endStageIndex: number;
70
+ }
71
+
72
+ function resolveOptions(options: ProcessBlueprintLayoutOptions | undefined): ResolvedLayoutOptions {
73
+ return { ...DEFAULTS, ...(options ?? {}) };
74
+ }
75
+
76
+ /**
77
+ * Greedy word-wrap to a max characters-per-line budget. Words longer than the
78
+ * budget are hard-split; if the result exceeds `maxLines`, the last kept line
79
+ * is truncated with an ellipsis so a single pathological cell can't grow the
80
+ * whole row unbounded.
81
+ */
82
+ function wrapText(text: string, maxChars: number, maxLines: number): string[] {
83
+ const trimmed = (text ?? '').trim();
84
+ if (trimmed.length === 0) return [];
85
+ const budget = Math.max(1, maxChars);
86
+
87
+ const words = trimmed.split(/\s+/);
88
+ const lines: string[] = [];
89
+ let cur = '';
90
+ const flush = (): void => {
91
+ if (cur.length > 0) {
92
+ lines.push(cur);
93
+ cur = '';
94
+ }
95
+ };
96
+
97
+ for (const word of words) {
98
+ if (word.length > budget) {
99
+ // Token wider than the cell: hard-break it across lines.
100
+ flush();
101
+ let rest = word;
102
+ while (rest.length > budget) {
103
+ lines.push(rest.slice(0, budget));
104
+ rest = rest.slice(budget);
105
+ }
106
+ cur = rest;
107
+ continue;
108
+ }
109
+ const candidate = cur.length > 0 ? `${cur} ${word}` : word;
110
+ if (candidate.length > budget) {
111
+ flush();
112
+ cur = word;
113
+ } else {
114
+ cur = candidate;
115
+ }
116
+ }
117
+ flush();
118
+
119
+ if (lines.length > maxLines) {
120
+ const capped = lines.slice(0, maxLines);
121
+ const last = capped[maxLines - 1];
122
+ const clipped = last.length > budget - 1 ? last.slice(0, budget - 1) : last;
123
+ capped[maxLines - 1] = `${clipped.replace(/…$/, '')}…`;
124
+ return capped;
125
+ }
126
+ return lines;
127
+ }
128
+
129
+ function buildStageIndex(stages: Stage[]): Map<string, number> {
130
+ const idx = new Map<string, number>();
131
+ for (let i = 0; i < stages.length; i++) {
132
+ const sid = typeof stages[i]?.id === 'string' ? stages[i].id.trim() : '';
133
+ if (sid.length > 0 && !idx.has(sid)) {
134
+ idx.set(sid, i);
135
+ }
136
+ }
137
+ return idx;
138
+ }
139
+
140
+ function pillsForEntry(
141
+ category: AspectCategory,
142
+ entryIndex: number,
143
+ entry: AspectEntry,
144
+ stageIndexById: Map<string, number>,
145
+ ): RawPill[] {
146
+ if (!Array.isArray(entry.stages)) return [];
147
+
148
+ const idxs: number[] = [];
149
+ const seen = new Set<number>();
150
+ for (const ref of entry.stages) {
151
+ if (typeof ref !== 'string') continue;
152
+ const i = stageIndexById.get(ref.trim());
153
+ if (i === undefined) continue;
154
+ if (seen.has(i)) continue;
155
+ seen.add(i);
156
+ idxs.push(i);
157
+ }
158
+ idxs.sort((a, b) => a - b);
159
+
160
+ const pills: RawPill[] = [];
161
+ let runStart: number | null = null;
162
+ let runEnd: number | null = null;
163
+ for (const i of idxs) {
164
+ if (runStart === null || runEnd === null) {
165
+ runStart = i;
166
+ runEnd = i;
167
+ continue;
168
+ }
169
+ if (i === runEnd + 1) {
170
+ runEnd = i;
171
+ } else {
172
+ pills.push({
173
+ category,
174
+ entryIndex,
175
+ name: entry.name,
176
+ id: entry.id,
177
+ startStageIndex: runStart,
178
+ endStageIndex: runEnd,
179
+ });
180
+ runStart = i;
181
+ runEnd = i;
182
+ }
183
+ }
184
+ if (runStart !== null && runEnd !== null) {
185
+ pills.push({
186
+ category,
187
+ entryIndex,
188
+ name: entry.name,
189
+ id: entry.id,
190
+ startStageIndex: runStart,
191
+ endStageIndex: runEnd,
192
+ });
193
+ }
194
+ return pills;
195
+ }
196
+
197
+ function packPillsIntoSlots(pills: RawPill[]): { slot: number[]; maxSlot: number } {
198
+ // Greedy interval scheduling: stable order by startStageIndex.
199
+ const order = pills
200
+ .map((_, i) => i)
201
+ .sort((a, b) => {
202
+ const ds = pills[a].startStageIndex - pills[b].startStageIndex;
203
+ if (ds !== 0) return ds;
204
+ return pills[a].endStageIndex - pills[b].endStageIndex;
205
+ });
206
+
207
+ const slotEndByLevel: number[] = []; // slotEndByLevel[s] = last endStageIndex placed in slot s
208
+ const slot = new Array<number>(pills.length).fill(0);
209
+ let maxSlot = 0;
210
+
211
+ for (const i of order) {
212
+ const p = pills[i];
213
+ let placed = false;
214
+ for (let s = 0; s < slotEndByLevel.length; s++) {
215
+ if (slotEndByLevel[s] < p.startStageIndex) {
216
+ slot[i] = s;
217
+ slotEndByLevel[s] = p.endStageIndex;
218
+ placed = true;
219
+ break;
220
+ }
221
+ }
222
+ if (!placed) {
223
+ slot[i] = slotEndByLevel.length;
224
+ slotEndByLevel.push(p.endStageIndex);
225
+ }
226
+ if (slot[i] > maxSlot) maxSlot = slot[i];
227
+ }
228
+
229
+ return { slot, maxSlot };
230
+ }
231
+
232
+ // ── Compliance lane derivation ────────────────────────────────────────────────
233
+
234
+ /** ISO 8601 date comparison helper — no Date parsing, string comparison is valid for YYYY-MM-DD. */
235
+ function deadlineStatus(
236
+ deadline: string | undefined,
237
+ today: string,
238
+ ): 'past_due' | 'in_force' | 'upcoming' | 'none' {
239
+ if (!deadline) return 'none';
240
+ if (deadline < today) return 'past_due';
241
+ const daysAway = Math.round(
242
+ (new Date(deadline).getTime() - new Date(today).getTime()) / (1000 * 60 * 60 * 24),
243
+ );
244
+ return daysAway <= 30 ? 'in_force' : 'upcoming';
245
+ }
246
+
247
+ /**
248
+ * Derive the laid-out compliance row for a process blueprint.
249
+ *
250
+ * For each stage, gathers the laws that bind that stage (via the
251
+ * assertion → requirement → derived_from chain), applies the jurisdiction
252
+ * filter, and computes the three orthogonal decorations per law chip.
253
+ */
254
+ function deriveComplianceRow(
255
+ stages: Stage[],
256
+ stageIndexById: Map<string, number>,
257
+ input: ComplianceLaneInput,
258
+ opts: ResolvedLayoutOptions,
259
+ yStart: number,
260
+ ): ComplianceRow | undefined {
261
+ const {
262
+ complianceLane: laneConfig,
263
+ legendColumnWidth,
264
+ stageColumnWidth,
265
+ cellPadding,
266
+ pillHeight,
267
+ pillGap,
268
+ aspectRowMinHeight,
269
+ } = opts;
270
+
271
+ if (!laneConfig?.enabled) return undefined;
272
+
273
+ const today = laneConfig.referenceDate ?? new Date().toISOString().slice(0, 10);
274
+ const filterJurisdictions = laneConfig.jurisdictions?.length ? new Set(laneConfig.jurisdictions) : null;
275
+
276
+ // Build requirement index: id → requirement.
277
+ const reqById = new Map<string, ComplianceLaneRequirement>();
278
+ for (const r of input.requirements) {
279
+ if (r?.id) reqById.set(r.id, r);
280
+ }
281
+
282
+ // Per-stage accumulation: stageIdx → lawId → { worstStatus, deadline }
283
+ type LawAccumulator = { gap: boolean; deadline: string | undefined };
284
+ const stageAccum = new Map<number, Map<string, LawAccumulator>>();
285
+
286
+ for (const a of input.assertions) {
287
+ if (!a || typeof a !== 'object') continue;
288
+ const realisedVia: string[] = Array.isArray(a.realised_via) ? a.realised_via : [];
289
+ if (realisedVia.length === 0) continue;
290
+
291
+ const req = reqById.get(a.about);
292
+ if (!req) continue;
293
+
294
+ const lawIds: string[] = Array.isArray(req.derived_from)
295
+ ? (req.derived_from as string[]).filter((x): x is string => typeof x === 'string')
296
+ : [];
297
+ if (lawIds.length === 0) continue;
298
+
299
+ for (const stageRef of realisedVia) {
300
+ if (typeof stageRef !== 'string') continue;
301
+ const idx = stageIndexById.get(stageRef.trim());
302
+ if (idx === undefined) continue;
303
+
304
+ for (const lawId of lawIds) {
305
+ // Apply jurisdiction filter.
306
+ if (filterJurisdictions) {
307
+ const jur = input.codexJurisdictions?.[lawId];
308
+ if (!jur || !filterJurisdictions.has(jur)) continue;
309
+ }
310
+
311
+ if (!stageAccum.has(idx)) stageAccum.set(idx, new Map());
312
+ const lawMap = stageAccum.get(idx)!;
313
+ const existing = lawMap.get(lawId);
314
+ const isGap = a.status === 'non_compliant' || a.status === 'partial';
315
+ if (!existing) {
316
+ lawMap.set(lawId, { gap: isGap, deadline: req.deadline });
317
+ } else {
318
+ existing.gap = existing.gap || isGap;
319
+ // Keep the earlier deadline (more urgent).
320
+ if (req.deadline && (!existing.deadline || req.deadline < existing.deadline)) {
321
+ existing.deadline = req.deadline;
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ if (stageAccum.size === 0) return undefined;
329
+
330
+ // Determine how many slots (rows) per stage.
331
+ const slotsPerStage = new Map<number, number>();
332
+ for (const [idx, lawMap] of stageAccum) {
333
+ slotsPerStage.set(idx, lawMap.size);
334
+ }
335
+ const maxSlots = Math.max(0, ...slotsPerStage.values());
336
+ if (maxSlots === 0) return undefined;
337
+
338
+ const contentHeight = maxSlots * (pillHeight + pillGap) - pillGap;
339
+ const rowHeight = Math.max(aspectRowMinHeight, contentHeight + 2 * cellPadding);
340
+
341
+ const chips: ComplianceChip[] = [];
342
+
343
+ for (const [stageIdx, lawMap] of stageAccum) {
344
+ const prevLawIds = new Set<string>(laneConfig.previousSnapshot?.[stages[stageIdx]?.id ?? ''] ?? []);
345
+ let slot = 0;
346
+
347
+ for (const [lawId, accum] of lawMap) {
348
+ const decorations: ComplianceDecoration[] = [];
349
+ if (!prevLawIds.has(lawId)) decorations.push('new');
350
+ if (accum.gap) {
351
+ decorations.push('gap');
352
+ const ds = deadlineStatus(accum.deadline, today);
353
+ if (ds !== 'none') decorations.push('deadline');
354
+ }
355
+
356
+ const x = legendColumnWidth + stageIdx * stageColumnWidth + cellPadding;
357
+ const width = stageColumnWidth - 2 * cellPadding;
358
+ const y = yStart + cellPadding + slot * (pillHeight + pillGap);
359
+ chips.push({ stageIndex: stageIdx, lawId, decorations, x, y, width, height: pillHeight });
360
+ slot++;
361
+ }
362
+ }
363
+
364
+ return { y: yStart, height: rowHeight, chips };
365
+ }
366
+
367
+ export function layoutProcessBlueprint(
368
+ file: ProcessBlueprintFile,
369
+ options?: ProcessBlueprintLayoutOptions,
370
+ ): ProcessBlueprintLayout {
371
+ const opts = resolveOptions(options);
372
+
373
+ const pb = file.process_blueprint;
374
+ const stages = Array.isArray(pb?.stages) ? pb.stages : [];
375
+ const stageIndexById = buildStageIndex(stages);
376
+
377
+ // Stage headers
378
+ const stageHeaders: StageHeaderCell[] = stages.map((s, i) => ({
379
+ stageIndex: i,
380
+ id: s?.id ?? '',
381
+ name: s?.name ?? '',
382
+ x: opts.legendColumnWidth + i * opts.stageColumnWidth,
383
+ y: 0,
384
+ width: opts.stageColumnWidth,
385
+ height: opts.stageHeaderHeight,
386
+ }));
387
+
388
+ // Goal + result rows. Text is word-wrapped to the column width, and each row
389
+ // grows to fit the tallest cell so nothing is clipped.
390
+ const maxCharsPerLine = Math.max(
391
+ 4,
392
+ Math.floor((opts.stageColumnWidth - 2 * opts.cellTextPadX) / opts.textCharWidth),
393
+ );
394
+ const wrap = (text: string): string[] => wrapText(text, maxCharsPerLine, opts.maxTextLines);
395
+ const rowHeightFor = (lineCounts: number[], minHeight: number): number => {
396
+ const maxLines = Math.max(1, ...lineCounts);
397
+ return Math.max(minHeight, maxLines * opts.textLineHeight + 2 * opts.cellTextPadY);
398
+ };
399
+
400
+ const goalLines = stages.map(s => wrap(s?.goal ?? ''));
401
+ const resultLines = stages.map(s => wrap(s?.result ?? ''));
402
+
403
+ const goalRowY = opts.stageHeaderHeight;
404
+ const goalRowHeight = rowHeightFor(goalLines.map(l => l.length), opts.goalRowHeight);
405
+ const resultRowY = goalRowY + goalRowHeight;
406
+ const resultRowHeight = rowHeightFor(resultLines.map(l => l.length), opts.resultRowHeight);
407
+
408
+ const goalCells: StageTextCell[] = stages.map((s, i) => ({
409
+ stageIndex: i,
410
+ text: s?.goal ?? '',
411
+ lines: goalLines[i],
412
+ x: opts.legendColumnWidth + i * opts.stageColumnWidth,
413
+ y: goalRowY,
414
+ width: opts.stageColumnWidth,
415
+ height: goalRowHeight,
416
+ }));
417
+
418
+ const resultCells: StageTextCell[] = stages.map((s, i) => ({
419
+ stageIndex: i,
420
+ text: s?.result ?? '',
421
+ lines: resultLines[i],
422
+ x: opts.legendColumnWidth + i * opts.stageColumnWidth,
423
+ y: resultRowY,
424
+ width: opts.stageColumnWidth,
425
+ height: resultRowHeight,
426
+ }));
427
+
428
+ const aspectsStartY = resultRowY + resultRowHeight;
429
+
430
+ // Aspect rows: only categories with at least one entry, in fixed order.
431
+ const aspectRows: AspectRow[] = [];
432
+ let aspectCursorY = aspectsStartY;
433
+
434
+ for (const category of ASPECT_CATEGORIES) {
435
+ const arr = pb?.[category];
436
+ if (!Array.isArray(arr) || arr.length === 0) continue;
437
+
438
+ const rawPills: RawPill[] = [];
439
+ for (let i = 0; i < arr.length; i++) {
440
+ const entry = arr[i];
441
+ if (!entry || typeof entry !== 'object') continue;
442
+ rawPills.push(...pillsForEntry(category, i, entry as AspectEntry, stageIndexById));
443
+ }
444
+
445
+ // If every entry in this category had no resolvable stage refs, drop the row.
446
+ if (rawPills.length === 0) continue;
447
+
448
+ const { slot, maxSlot } = packPillsIntoSlots(rawPills);
449
+ const contentHeight = (maxSlot + 1) * (opts.pillHeight + opts.pillGap) - opts.pillGap;
450
+ const rowHeight = Math.max(
451
+ opts.aspectRowMinHeight,
452
+ contentHeight + 2 * opts.cellPadding,
453
+ );
454
+
455
+ const pills: AspectPill[] = rawPills.map((p, i) => {
456
+ const x = opts.legendColumnWidth + p.startStageIndex * opts.stageColumnWidth + opts.cellPadding;
457
+ const width =
458
+ (p.endStageIndex - p.startStageIndex + 1) * opts.stageColumnWidth - 2 * opts.cellPadding;
459
+ const y = aspectCursorY + opts.cellPadding + slot[i] * (opts.pillHeight + opts.pillGap);
460
+ return {
461
+ category: p.category,
462
+ entryIndex: p.entryIndex,
463
+ name: p.name,
464
+ id: p.id,
465
+ startStageIndex: p.startStageIndex,
466
+ endStageIndex: p.endStageIndex,
467
+ x,
468
+ y,
469
+ width,
470
+ height: opts.pillHeight,
471
+ };
472
+ });
473
+
474
+ aspectRows.push({
475
+ category,
476
+ y: aspectCursorY,
477
+ height: rowHeight,
478
+ pills,
479
+ });
480
+
481
+ aspectCursorY += rowHeight;
482
+ }
483
+
484
+ // Compliance lane — derived from assertions/requirements, rendered after aspect rows.
485
+ let complianceRow: import('./types.js').ComplianceRow | undefined;
486
+ if (opts.complianceLane?.enabled && opts.complianceInput) {
487
+ complianceRow = deriveComplianceRow(
488
+ stages,
489
+ stageIndexById,
490
+ opts.complianceInput,
491
+ opts,
492
+ aspectCursorY,
493
+ );
494
+ if (complianceRow) {
495
+ aspectCursorY += complianceRow.height;
496
+ }
497
+ }
498
+
499
+ // Legend (left column labels): one entry per row.
500
+ const legend: LegendCell[] = [
501
+ { kind: 'goal', label: 'Goal', y: goalRowY, height: goalRowHeight },
502
+ { kind: 'result', label: 'Result', y: resultRowY, height: resultRowHeight },
503
+ ...aspectRows.map<LegendCell>(row => ({
504
+ kind: 'aspect',
505
+ category: row.category,
506
+ label: ASPECT_LABEL[row.category],
507
+ y: row.y,
508
+ height: row.height,
509
+ })),
510
+ ...(complianceRow
511
+ ? [{ kind: 'compliance' as const, label: 'Compliance', y: complianceRow.y, height: complianceRow.height }]
512
+ : []),
513
+ ];
514
+
515
+ const totalWidth = opts.legendColumnWidth + stages.length * opts.stageColumnWidth;
516
+ const totalHeight = aspectCursorY;
517
+
518
+ return {
519
+ bounds: { x: 0, y: 0, width: totalWidth, height: totalHeight },
520
+ legendColumnWidth: opts.legendColumnWidth,
521
+ stageColumnWidth: opts.stageColumnWidth,
522
+ textLineHeight: opts.textLineHeight,
523
+ cellTextPadX: opts.cellTextPadX,
524
+ legend,
525
+ stageHeaders,
526
+ goalCells,
527
+ resultCells,
528
+ aspectRows,
529
+ complianceRow,
530
+ };
531
+ }