@transitrix/diagrams 1.0.0 → 1.1.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 (315) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +47 -47
  3. package/dist/__tests__/edge-path.test.js +8 -0
  4. package/dist/activities/cpm.js +11 -2
  5. package/dist/activities/gantt.js +6 -3
  6. package/dist/activities/types.d.ts +1 -0
  7. package/dist/activities/validate.js +3 -3
  8. package/dist/activity-card/__tests__/example.test.js +20 -1
  9. package/dist/activity-card/__tests__/layout.test.js +102 -11
  10. package/dist/activity-card/__tests__/resolver.test.js +161 -7
  11. package/dist/activity-card/index.d.ts +1 -1
  12. package/dist/activity-card/layout.d.ts +1 -1
  13. package/dist/activity-card/layout.js +220 -103
  14. package/dist/activity-card/resolver.js +115 -28
  15. package/dist/activity-card/types.d.ts +150 -27
  16. package/dist/activity-card/validate.js +3 -0
  17. package/dist/actor/__tests__/validate.test.js +63 -31
  18. package/dist/actor/index.d.ts +1 -1
  19. package/dist/actor/index.js +1 -1
  20. package/dist/actor/types.d.ts +7 -3
  21. package/dist/actor/types.js +17 -3
  22. package/dist/actor/validate.js +55 -26
  23. package/dist/assertion/types.d.ts +3 -1
  24. package/dist/assertion/types.js +1 -1
  25. package/dist/change/__tests__/validate.test.js +40 -34
  26. package/dist/change/index.d.ts +1 -0
  27. package/dist/change/types.d.ts +1 -1
  28. package/dist/change/types.js +2 -2
  29. package/dist/change/validate.d.ts +6 -1
  30. package/dist/change/validate.js +68 -41
  31. package/dist/compliance/__tests__/classify.test.js +34 -0
  32. package/dist/compliance/__tests__/coverage-metric.test.js +146 -46
  33. package/dist/compliance/__tests__/html.test.js +2 -2
  34. package/dist/compliance/__tests__/impact.test.js +509 -6
  35. package/dist/compliance/classify.d.ts +6 -0
  36. package/dist/compliance/classify.js +9 -1
  37. package/dist/compliance/coverage-metric.d.ts +31 -11
  38. package/dist/compliance/coverage-metric.js +149 -39
  39. package/dist/compliance/html.js +78 -81
  40. package/dist/compliance/impact.d.ts +100 -16
  41. package/dist/compliance/impact.js +272 -28
  42. package/dist/compliance/index.d.ts +2 -2
  43. package/dist/compliance/index.js +1 -1
  44. package/dist/compliance/markdown.js +1 -0
  45. package/dist/compliance/types.d.ts +25 -6
  46. package/dist/edge-path.d.ts +8 -4
  47. package/dist/edge-path.js +11 -6
  48. package/dist/factor/__tests__/validate.test.js +75 -46
  49. package/dist/factor/index.d.ts +3 -2
  50. package/dist/factor/index.js +1 -1
  51. package/dist/factor/types.d.ts +5 -8
  52. package/dist/factor/types.js +10 -5
  53. package/dist/factor/validate.d.ts +6 -1
  54. package/dist/factor/validate.js +68 -50
  55. package/dist/fgca/__tests__/chain-table.test.js +2 -2
  56. package/dist/fgca/__tests__/layout.test.js +11 -11
  57. package/dist/fgca/__tests__/preview-layout.test.js +7 -7
  58. package/dist/fgca/__tests__/resolver.test.js +185 -0
  59. package/dist/fgca/chain-table.d.ts +1 -1
  60. package/dist/fgca/chain-table.js +4 -4
  61. package/dist/fgca/index.d.ts +4 -2
  62. package/dist/fgca/index.js +2 -1
  63. package/dist/fgca/layout.d.ts +2 -2
  64. package/dist/fgca/layout.js +9 -9
  65. package/dist/fgca/nodeTypes.d.ts +1 -1
  66. package/dist/fgca/nodeTypes.js +2 -2
  67. package/dist/fgca/nodes/FGCAFactorNode.d.ts +3 -3
  68. package/dist/fgca/nodes/FGCAFactorNode.js +5 -5
  69. package/dist/fgca/parse-canonical.js +15 -10
  70. package/dist/fgca/preview-layout.d.ts +1 -1
  71. package/dist/fgca/preview-layout.js +4 -4
  72. package/dist/fgca/resolver.d.ts +49 -0
  73. package/dist/fgca/resolver.js +126 -0
  74. package/dist/fgca/types.d.ts +11 -11
  75. package/dist/fgca/types.js +2 -2
  76. package/dist/fgca/validate.d.ts +2 -2
  77. package/dist/fgca/validate.js +17 -14
  78. package/dist/goals/index.d.ts +1 -1
  79. package/dist/index.d.ts +5 -0
  80. package/dist/index.js +5 -0
  81. package/dist/process-blueprint/__tests__/layout.test.js +37 -0
  82. package/dist/process-blueprint/index.d.ts +1 -1
  83. package/dist/process-blueprint/layout.js +66 -35
  84. package/dist/process-blueprint/types.d.ts +36 -1
  85. package/dist/scenarios/index.d.ts +1 -1
  86. package/dist/scenarios/types.d.ts +4 -4
  87. package/dist/stakeholder/__tests__/validate.test.js +49 -47
  88. package/dist/stakeholder/index.d.ts +1 -0
  89. package/dist/stakeholder/types.d.ts +3 -4
  90. package/dist/stakeholder/types.js +2 -3
  91. package/dist/stakeholder/validate.d.ts +6 -1
  92. package/dist/stakeholder/validate.js +71 -50
  93. package/dist/target-state/__tests__/validate.test.js +43 -27
  94. package/dist/target-state/index.d.ts +2 -0
  95. package/dist/target-state/index.js +1 -0
  96. package/dist/target-state/types.d.ts +6 -1
  97. package/dist/target-state/types.js +8 -7
  98. package/dist/target-state/validate.d.ts +6 -1
  99. package/dist/target-state/validate.js +69 -45
  100. package/dist/theme/themes.js +71 -69
  101. package/dist/theme/tokens.d.ts +7 -1
  102. package/dist/theme/tokens.js +3 -1
  103. package/dist/webview/__tests__/entry-notations.test.js +2 -0
  104. package/dist/webview/__tests__/entry.test.js +11 -11
  105. package/dist/webview/__tests__/render-process.test.js +463 -0
  106. package/dist/webview/__tests__/render-util.test.d.ts +1 -0
  107. package/dist/webview/__tests__/render-util.test.js +54 -0
  108. package/dist/webview/entry.d.ts +1 -1
  109. package/dist/webview/entry.js +9 -5
  110. package/dist/webview/render-activities.d.ts +24 -2
  111. package/dist/webview/render-activities.js +92 -57
  112. package/dist/webview/render-activity-card.d.ts +11 -1
  113. package/dist/webview/render-activity-card.js +115 -79
  114. package/dist/webview/render-blocks.d.ts +24 -1
  115. package/dist/webview/render-blocks.js +58 -24
  116. package/dist/webview/render-fgca.d.ts +31 -0
  117. package/dist/webview/render-fgca.js +30 -19
  118. package/dist/webview/render-goals.d.ts +27 -1
  119. package/dist/webview/render-goals.js +42 -32
  120. package/dist/webview/render-process-blueprint.d.ts +11 -1
  121. package/dist/webview/render-process-blueprint.js +118 -53
  122. package/dist/webview/render-process.d.ts +95 -0
  123. package/dist/webview/render-process.js +392 -0
  124. package/dist/webview/render-scenarios.js +2 -2
  125. package/dist/webview/render-util.d.ts +19 -6
  126. package/dist/webview/render-util.js +23 -15
  127. package/package.json +54 -40
  128. package/src/__tests__/edge-path.test.ts +58 -46
  129. package/src/__tests__/scope.test.ts +27 -27
  130. package/src/__tests__/yaml-normalize.test.ts +158 -158
  131. package/src/activities/__tests__/cpm.test.ts +164 -164
  132. package/src/activities/__tests__/gantt.test.ts +245 -245
  133. package/src/activities/__tests__/layout.test.ts +112 -112
  134. package/src/activities/__tests__/validate.test.ts +409 -409
  135. package/src/activities/cpm.ts +107 -95
  136. package/src/activities/gantt.ts +277 -276
  137. package/src/activities/index.ts +28 -28
  138. package/src/activities/layout.ts +112 -112
  139. package/src/activities/types.ts +149 -148
  140. package/src/activities/validate.ts +357 -357
  141. package/src/activity-card/__tests__/example.test.ts +85 -66
  142. package/src/activity-card/__tests__/layout.test.ts +169 -63
  143. package/src/activity-card/__tests__/resolver.test.ts +330 -161
  144. package/src/activity-card/__tests__/validate.test.ts +131 -131
  145. package/src/activity-card/index.ts +38 -32
  146. package/src/activity-card/layout.ts +324 -194
  147. package/src/activity-card/resolver.ts +422 -337
  148. package/src/activity-card/types.ts +376 -237
  149. package/src/activity-card/validate.ts +162 -158
  150. package/src/actor/__tests__/validate.test.ts +70 -31
  151. package/src/actor/index.ts +1 -1
  152. package/src/actor/types.ts +21 -7
  153. package/src/actor/validate.ts +59 -27
  154. package/src/applications/__tests__/validate.test.ts +256 -256
  155. package/src/applications/index.ts +11 -11
  156. package/src/applications/types.ts +43 -43
  157. package/src/applications/validate.ts +131 -131
  158. package/src/assertion/__tests__/example.test.ts +37 -37
  159. package/src/assertion/__tests__/validate.test.ts +142 -142
  160. package/src/assertion/index.ts +12 -12
  161. package/src/assertion/types.ts +60 -58
  162. package/src/assertion/validate.ts +145 -145
  163. package/src/blocks/__tests__/layout.test.ts +169 -169
  164. package/src/blocks/__tests__/validate.test.ts +260 -260
  165. package/src/blocks/index.ts +17 -17
  166. package/src/blocks/layout.ts +186 -186
  167. package/src/blocks/types.ts +62 -62
  168. package/src/blocks/validate.ts +206 -206
  169. package/src/capability-map/__tests__/validate.test.ts +238 -238
  170. package/src/capability-map/index.ts +8 -8
  171. package/src/capability-map/types.ts +29 -29
  172. package/src/capability-map/validate.ts +127 -127
  173. package/src/change/__tests__/validate.test.ts +43 -34
  174. package/src/change/index.ts +1 -0
  175. package/src/change/types.ts +5 -3
  176. package/src/change/validate.ts +75 -43
  177. package/src/compliance/__tests__/classify.test.ts +64 -27
  178. package/src/compliance/__tests__/confidence.test.ts +98 -98
  179. package/src/compliance/__tests__/coverage-metric.test.ts +300 -188
  180. package/src/compliance/__tests__/demo-scenario.test.ts +273 -273
  181. package/src/compliance/__tests__/example.test.ts +57 -57
  182. package/src/compliance/__tests__/gap-report.test.ts +128 -128
  183. package/src/compliance/__tests__/html.test.ts +141 -141
  184. package/src/compliance/__tests__/impact.test.ts +1059 -481
  185. package/src/compliance/__tests__/markdown.test.ts +94 -94
  186. package/src/compliance/__tests__/views.test.ts +64 -64
  187. package/src/compliance/classify.ts +100 -84
  188. package/src/compliance/confidence.ts +69 -69
  189. package/src/compliance/coverage-metric.ts +404 -263
  190. package/src/compliance/gap-report.ts +94 -94
  191. package/src/compliance/html.ts +291 -295
  192. package/src/compliance/impact.ts +979 -677
  193. package/src/compliance/index.ts +57 -56
  194. package/src/compliance/markdown.ts +136 -135
  195. package/src/compliance/reverse-index.ts +33 -33
  196. package/src/compliance/types.ts +136 -120
  197. package/src/compliance/views.ts +46 -46
  198. package/src/compliance-matrix/__tests__/build.test.ts +200 -200
  199. package/src/compliance-matrix/__tests__/example.test.ts +57 -57
  200. package/src/compliance-matrix/index.ts +11 -11
  201. package/src/compliance-matrix/types.ts +102 -102
  202. package/src/edge-path.ts +50 -44
  203. package/src/factor/__tests__/validate.test.ts +81 -46
  204. package/src/factor/index.ts +3 -7
  205. package/src/factor/types.ts +15 -19
  206. package/src/factor/validate.ts +77 -51
  207. package/src/fgca/__tests__/chain-table.test.ts +172 -172
  208. package/src/fgca/__tests__/layout.test.ts +179 -179
  209. package/src/fgca/__tests__/parse-canonical.test.ts +248 -248
  210. package/src/fgca/__tests__/preview-layout.test.ts +124 -124
  211. package/src/fgca/__tests__/resolver.test.ts +209 -0
  212. package/src/fgca/__tests__/validate.test.ts +142 -142
  213. package/src/fgca/chain-table.ts +225 -225
  214. package/src/fgca/index.ts +47 -45
  215. package/src/fgca/layout.ts +204 -204
  216. package/src/fgca/nodeTypes.ts +11 -11
  217. package/src/fgca/nodes/FGCAActivityNode.tsx +65 -65
  218. package/src/fgca/nodes/FGCAChangeNode.tsx +64 -64
  219. package/src/fgca/nodes/FGCAFactorNode.tsx +64 -64
  220. package/src/fgca/nodes/FGCAGoalNode.tsx +72 -72
  221. package/src/fgca/parse-canonical.ts +405 -400
  222. package/src/fgca/preview-layout.ts +217 -217
  223. package/src/fgca/resolver.ts +159 -0
  224. package/src/fgca/types.ts +50 -50
  225. package/src/fgca/validate.ts +129 -126
  226. package/src/geometry.ts +9 -9
  227. package/src/goals/__tests__/layout.test.ts +175 -175
  228. package/src/goals/__tests__/mutations.test.ts +111 -111
  229. package/src/goals/__tests__/parse-canonical.test.ts +145 -145
  230. package/src/goals/__tests__/validate.test.ts +202 -202
  231. package/src/goals/index.ts +20 -21
  232. package/src/goals/layout.ts +172 -172
  233. package/src/goals/mutations.ts +123 -123
  234. package/src/goals/parse-canonical.ts +286 -286
  235. package/src/goals/types.ts +85 -85
  236. package/src/goals/validate.ts +136 -136
  237. package/src/index.ts +28 -23
  238. package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -320
  239. package/src/process-blueprint/__tests__/layout.test.ts +240 -195
  240. package/src/process-blueprint/__tests__/validate.test.ts +310 -310
  241. package/src/process-blueprint/index.ts +32 -31
  242. package/src/process-blueprint/layout.ts +564 -531
  243. package/src/process-blueprint/types.ts +278 -242
  244. package/src/process-blueprint/validate.ts +181 -181
  245. package/src/process-map/__tests__/validate.test.ts +223 -223
  246. package/src/process-map/index.ts +10 -10
  247. package/src/process-map/types.ts +36 -36
  248. package/src/process-map/validate.ts +135 -135
  249. package/src/products/__tests__/validate.test.ts +239 -239
  250. package/src/products/index.ts +9 -9
  251. package/src/products/types.ts +31 -31
  252. package/src/products/validate.ts +112 -112
  253. package/src/repo-validate/__tests__/validate-repo.test.ts +149 -149
  254. package/src/repo-validate/index.ts +2 -2
  255. package/src/repo-validate/types.ts +50 -50
  256. package/src/repo-validate/validate-repo.ts +196 -196
  257. package/src/requirement/__tests__/example.test.ts +24 -24
  258. package/src/requirement/__tests__/validate.test.ts +96 -96
  259. package/src/requirement/index.ts +4 -4
  260. package/src/requirement/types.ts +35 -35
  261. package/src/requirement/validate.ts +92 -92
  262. package/src/scenarios/__tests__/validate.test.ts +209 -209
  263. package/src/scenarios/index.ts +15 -15
  264. package/src/scenarios/types.ts +37 -37
  265. package/src/scenarios/validate.ts +122 -122
  266. package/src/schema-version.ts +16 -16
  267. package/src/scope.ts +46 -46
  268. package/src/stakeholder/__tests__/validate.test.ts +51 -47
  269. package/src/stakeholder/index.ts +1 -0
  270. package/src/stakeholder/types.ts +7 -7
  271. package/src/stakeholder/validate.ts +79 -52
  272. package/src/target-state/__tests__/validate.test.ts +48 -27
  273. package/src/target-state/index.ts +2 -0
  274. package/src/target-state/types.ts +11 -7
  275. package/src/target-state/validate.ts +76 -46
  276. package/src/theme/index.ts +4 -4
  277. package/src/theme/themes.ts +239 -237
  278. package/src/theme/tokens.ts +135 -133
  279. package/src/typed-id.ts +56 -56
  280. package/src/validation-types.ts +36 -36
  281. package/src/webview/__tests__/entry-notations.test.ts +79 -77
  282. package/src/webview/__tests__/entry.test.ts +64 -64
  283. package/src/webview/__tests__/render-goals.test.ts +72 -72
  284. package/src/webview/__tests__/render-process.test.ts +538 -0
  285. package/src/webview/__tests__/render-util.test.ts +66 -0
  286. package/src/webview/entry.ts +298 -292
  287. package/src/webview/render-activities.ts +111 -69
  288. package/src/webview/render-activity-card.ts +275 -234
  289. package/src/webview/render-blocks.ts +78 -28
  290. package/src/webview/render-fgca.ts +53 -28
  291. package/src/webview/render-goals.ts +133 -110
  292. package/src/webview/render-process-blueprint.ts +281 -207
  293. package/src/webview/render-process.ts +507 -0
  294. package/src/webview/render-scenarios.ts +3 -3
  295. package/src/webview/render-util.ts +27 -14
  296. package/src/webview/styles.css +322 -323
  297. package/src/yaml-normalize.ts +56 -56
  298. package/dist/element-envelope.d.ts +0 -15
  299. package/dist/element-envelope.js +0 -55
  300. package/dist/issues/__tests__/layout.test.js +0 -62
  301. package/dist/issues/__tests__/validate.test.js +0 -82
  302. package/dist/issues/index.d.ts +0 -4
  303. package/dist/issues/index.js +0 -2
  304. package/dist/issues/layout.d.ts +0 -10
  305. package/dist/issues/layout.js +0 -82
  306. package/dist/issues/types.d.ts +0 -61
  307. package/dist/issues/types.js +0 -6
  308. package/dist/issues/validate.d.ts +0 -3
  309. package/dist/issues/validate.js +0 -143
  310. package/dist/webview/transitrix-render.css +0 -323
  311. package/dist/webview/transitrix-render.js +0 -6452
  312. package/dist/webview/transitrix-render.js.map +0 -7
  313. package/src/element-envelope.ts +0 -76
  314. /package/dist/{issues/__tests__/layout.test.d.ts → fgca/__tests__/resolver.test.d.ts} +0 -0
  315. /package/dist/{issues/__tests__/validate.test.d.ts → webview/__tests__/render-process.test.d.ts} +0 -0
@@ -0,0 +1,126 @@
1
+ /**
2
+ * FGCA canon resolver — assembles a flat canonical FGCA document from a
3
+ * view_config projection and a canon element/relation store (VP-3).
4
+ *
5
+ * Output shape matches the flat form that `parseCanonicalFGCA` expects:
6
+ * top-level `factors[]`, `goals[]`, `changes[]`, `activities[]` with typed
7
+ * string IDs. Filesystem-free — callable from unit tests without vscode.
8
+ */
9
+ function isObject(v) {
10
+ return !!v && typeof v === 'object' && !Array.isArray(v);
11
+ }
12
+ function str(v) {
13
+ return typeof v === 'string' && v.trim().length > 0 ? v : undefined;
14
+ }
15
+ function strArray(v) {
16
+ if (!Array.isArray(v))
17
+ return [];
18
+ return v.filter((x) => typeof x === 'string' && x.trim().length > 0);
19
+ }
20
+ function collectByNotation(docs, notation) {
21
+ const out = new Map();
22
+ for (const doc of docs) {
23
+ if (!isObject(doc))
24
+ continue;
25
+ if (str(doc['notation']) !== notation)
26
+ continue;
27
+ const id = str(doc['id']);
28
+ if (!id)
29
+ continue;
30
+ if (!out.has(id))
31
+ out.set(id, doc);
32
+ }
33
+ return out;
34
+ }
35
+ /**
36
+ * Returns true when the parsed view document uses the canon-projection form
37
+ * (`view_config` key present, no inline `factors[]` / `goals[]` arrays).
38
+ * Used by the preview to decide whether to run the resolver or fall back to
39
+ * direct `parseCanonicalFGCA` on the inline document.
40
+ */
41
+ export function isFGCAViewDoc(parsed) {
42
+ if (!isObject(parsed))
43
+ return false;
44
+ return 'view_config' in parsed && !('factors' in parsed) && !('goals' in parsed);
45
+ }
46
+ /**
47
+ * Assemble a flat canonical FGCA document from the canon element store,
48
+ * filtered by the view document's `view_config`. The return value is ready
49
+ * to pass to `parseCanonicalFGCA`.
50
+ *
51
+ * Cross-reference fields (`goal.factors[]`, `change.goals[]`,
52
+ * `activity.changes[]`) are carried from the canon elements unchanged; the
53
+ * resolver decides which elements to include, not how they are shaped.
54
+ */
55
+ export function resolveFGCA(viewDoc, sources) {
56
+ if (!isObject(viewDoc)) {
57
+ return { notation: 'fgca', factors: [], goals: [], changes: [], activities: [] };
58
+ }
59
+ const vc = isObject(viewDoc['view_config']) ? viewDoc['view_config'] : {};
60
+ const goalsConf = isObject(vc['goals']) ? vc['goals'] : {};
61
+ const factorsConf = isObject(vc['factors']) ? vc['factors'] : {};
62
+ const changesConf = isObject(vc['changes']) ? vc['changes'] : {};
63
+ const activitiesConf = isObject(vc['activities']) ? vc['activities'] : {};
64
+ const factorElemsLegacy = collectByNotation(sources.elements, 'factor');
65
+ const factorElemsNew = collectByNotation(sources.elements, 'driver');
66
+ const factorElems = new Map([...factorElemsLegacy, ...factorElemsNew]);
67
+ const goalElems = collectByNotation(sources.elements, 'goal');
68
+ const changeElems = collectByNotation(sources.elements, 'change');
69
+ const activityElems = collectByNotation(sources.elements, 'activity');
70
+ // 1. Select goal set
71
+ const goalsFilter = str(goalsConf['filter']) ?? 'all';
72
+ let selectedGoals;
73
+ if (goalsFilter === 'ids') {
74
+ const ids = strArray(goalsConf['ids']);
75
+ selectedGoals = ids.flatMap((id) => { const g = goalElems.get(id); return g ? [g] : []; });
76
+ }
77
+ else if (goalsFilter === 'tags') {
78
+ const tags = strArray(goalsConf['tags']);
79
+ selectedGoals = [...goalElems.values()].filter((g) => strArray(g['tags']).some((t) => tags.includes(t)));
80
+ }
81
+ else {
82
+ // 'all' — include every goal element in the canon store
83
+ selectedGoals = [...goalElems.values()];
84
+ }
85
+ const selectedGoalIds = new Set(selectedGoals.map((g) => str(g['id'])).filter((x) => x !== undefined));
86
+ // 2. Select factors: derived follows goal.factors[]; all = every factor
87
+ let selectedFactors;
88
+ if (str(factorsConf['surface']) === 'all') {
89
+ selectedFactors = [...factorElems.values()];
90
+ }
91
+ else {
92
+ const refIds = new Set();
93
+ for (const g of selectedGoals)
94
+ for (const fid of strArray(g['factors']))
95
+ refIds.add(fid);
96
+ selectedFactors = [...refIds].flatMap((id) => { const f = factorElems.get(id); return f ? [f] : []; });
97
+ }
98
+ // 3. Select changes: derived = changes referencing ≥1 selected goal
99
+ let selectedChanges;
100
+ if (str(changesConf['surface']) === 'all') {
101
+ selectedChanges = [...changeElems.values()];
102
+ }
103
+ else {
104
+ selectedChanges = [...changeElems.values()].filter((c) => strArray(c['goals']).some((gid) => selectedGoalIds.has(gid)));
105
+ }
106
+ const selectedChangeIds = new Set(selectedChanges.map((c) => str(c['id'])).filter((x) => x !== undefined));
107
+ // 4. Select activities: derived = reference ≥1 selected change or goal (degenerate FGA link)
108
+ let selectedActivities;
109
+ if (str(activitiesConf['surface']) === 'all') {
110
+ selectedActivities = [...activityElems.values()];
111
+ }
112
+ else {
113
+ selectedActivities = [...activityElems.values()].filter((a) => strArray(a['changes']).some((cid) => selectedChangeIds.has(cid)) ||
114
+ strArray(a['goals']).some((gid) => selectedGoalIds.has(gid)));
115
+ }
116
+ return {
117
+ notation: 'fgca',
118
+ id: viewDoc['id'],
119
+ name: viewDoc['name'],
120
+ spec_version: viewDoc['spec_version'],
121
+ factors: selectedFactors,
122
+ goals: selectedGoals,
123
+ changes: selectedChanges,
124
+ activities: selectedActivities,
125
+ };
126
+ }
@@ -1,30 +1,30 @@
1
- export interface FactorItem {
2
- id: number;
1
+ export interface DriverItem {
2
+ id: number | string;
3
3
  name: string;
4
4
  }
5
5
  export interface GoalItem {
6
- id: number;
6
+ id: number | string;
7
7
  name: string;
8
8
  level?: number;
9
9
  /** Goals may carry embedded factor links returned by the API. */
10
10
  factor?: Array<{
11
- id: number;
11
+ id: number | string;
12
12
  }>;
13
13
  }
14
14
  export interface BdnChangeWithActivities {
15
- id: number;
15
+ id: number | string;
16
16
  name: string;
17
- goal_id: number;
18
- activity_ids: number[];
17
+ goal_id: number | string;
18
+ activity_ids: Array<number | string>;
19
19
  }
20
20
  export interface ActivityItem {
21
- id: number;
21
+ id: number | string;
22
22
  name: string;
23
- goal_id?: number | null;
23
+ goal_id?: number | string | null;
24
24
  activity_type_id?: number;
25
25
  }
26
26
  export interface ActivityTypeItem {
27
- id: number;
27
+ id: number | string;
28
28
  name?: string;
29
29
  }
30
30
  export interface DiagramStyle {
@@ -34,6 +34,6 @@ export interface DiagramStyle {
34
34
  edgeWidth?: number;
35
35
  }
36
36
  /** The four columns of the FGCA diagram. */
37
- export type FGCAColumn = "factor" | "goal" | "change" | "activity";
37
+ export type FGCAColumn = "driver" | "goal" | "change" | "activity";
38
38
  export declare const ALL_FGCA_COLUMNS: FGCAColumn[];
39
39
  export declare const FGCA_COLUMN_LABELS: Record<FGCAColumn, string>;
@@ -1,6 +1,6 @@
1
- export const ALL_FGCA_COLUMNS = ["factor", "goal", "change", "activity"];
1
+ export const ALL_FGCA_COLUMNS = ["driver", "goal", "change", "activity"];
2
2
  export const FGCA_COLUMN_LABELS = {
3
- factor: "F",
3
+ driver: "D",
4
4
  goal: "G",
5
5
  change: "C",
6
6
  activity: "A",
@@ -1,4 +1,4 @@
1
- import type { FactorItem, GoalItem, BdnChangeWithActivities, ActivityItem } from './types.js';
1
+ import type { DriverItem, GoalItem, BdnChangeWithActivities, ActivityItem } from './types.js';
2
2
  import type { ValidationError, ValidationWarning, ValidationResult } from '../validation-types.js';
3
3
  export type FGCAValidationError = ValidationError;
4
4
  export type FGCAValidationWarning = ValidationWarning;
@@ -6,7 +6,7 @@ export type FGCAValidationResult = ValidationResult;
6
6
  export interface FGCADoc {
7
7
  notation: string;
8
8
  spec_version?: string;
9
- factors: FactorItem[];
9
+ factors: DriverItem[];
10
10
  goals: GoalItem[];
11
11
  changes: BdnChangeWithActivities[];
12
12
  activities: ActivityItem[];
@@ -9,10 +9,13 @@ export function validateFGCADoc(input) {
9
9
  errors.push({ code: 'MISSING_NOTATION', message: 'notation field is required' });
10
10
  return { valid: false, errors, warnings };
11
11
  }
12
- if (raw.notation !== 'fgca') {
13
- errors.push({ code: 'WRONG_NOTATION', message: `notation must be "fgca", got "${String(raw.notation)}"` });
12
+ if (raw.notation !== 'fgca' && raw.notation !== 'dgca') {
13
+ errors.push({ code: 'WRONG_NOTATION', message: `notation must be "dgca" (or legacy "fgca"), got "${String(raw.notation)}"` });
14
14
  return { valid: false, errors, warnings };
15
15
  }
16
+ if (raw.notation === 'fgca') {
17
+ warnings.push({ code: 'DEPRECATED_NOTATION', message: 'notation "fgca" is deprecated — rename to "dgca"' });
18
+ }
16
19
  if (!Array.isArray(raw.factors))
17
20
  errors.push({ code: 'SCHEMA_INVALID', message: 'factors must be an array', path: 'factors' });
18
21
  if (!Array.isArray(raw.goals))
@@ -29,7 +32,7 @@ export function validateFGCADoc(input) {
29
32
  for (const el of arr) {
30
33
  if (el && typeof el === 'object') {
31
34
  const id = el.id;
32
- if (typeof id === 'number')
35
+ if (typeof id === 'number' || typeof id === 'string')
33
36
  out.add(id);
34
37
  }
35
38
  }
@@ -45,8 +48,8 @@ export function validateFGCADoc(input) {
45
48
  continue;
46
49
  }
47
50
  const factor = f;
48
- if (typeof factor.id !== 'number')
49
- errors.push({ code: 'SCHEMA_INVALID', message: 'factor id must be a number', path: `factors[${i}]` });
51
+ if (typeof factor.id !== 'number' && typeof factor.id !== 'string')
52
+ errors.push({ code: 'SCHEMA_INVALID', message: 'factor id must be a number or string', path: `factors[${i}]` });
50
53
  if (typeof factor.name !== 'string' || !factor.name.trim())
51
54
  errors.push({ code: 'EMPTY_NAME', message: `Factor ${String(factor.id)} has empty name`, path: `factors[${i}]` });
52
55
  }
@@ -57,8 +60,8 @@ export function validateFGCADoc(input) {
57
60
  continue;
58
61
  }
59
62
  const goal = g;
60
- if (typeof goal.id !== 'number')
61
- errors.push({ code: 'SCHEMA_INVALID', message: 'goal id must be a number', path: `goals[${i}]` });
63
+ if (typeof goal.id !== 'number' && typeof goal.id !== 'string')
64
+ errors.push({ code: 'SCHEMA_INVALID', message: 'goal id must be a number or string', path: `goals[${i}]` });
62
65
  if (typeof goal.name !== 'string' || !goal.name.trim())
63
66
  errors.push({ code: 'EMPTY_NAME', message: `Goal ${String(goal.id)} has empty name`, path: `goals[${i}]` });
64
67
  const factorRefs = Array.isArray(goal.factor) ? goal.factor : [];
@@ -66,7 +69,7 @@ export function validateFGCADoc(input) {
66
69
  if (!fr || typeof fr !== 'object')
67
70
  continue;
68
71
  const fid = fr.id;
69
- if (typeof fid === 'number' && !factorIds.has(fid)) {
72
+ if ((typeof fid === 'number' || typeof fid === 'string') && !factorIds.has(fid)) {
70
73
  warnings.push({ code: 'BROKEN_REF', message: `Goal ${String(goal.id)} references missing factor ${fid}`, path: `goals[${i}].factor` });
71
74
  }
72
75
  }
@@ -78,16 +81,16 @@ export function validateFGCADoc(input) {
78
81
  continue;
79
82
  }
80
83
  const change = c;
81
- if (typeof change.id !== 'number')
82
- errors.push({ code: 'SCHEMA_INVALID', message: 'change id must be a number', path: `changes[${i}]` });
84
+ if (typeof change.id !== 'number' && typeof change.id !== 'string')
85
+ errors.push({ code: 'SCHEMA_INVALID', message: 'change id must be a number or string', path: `changes[${i}]` });
83
86
  if (typeof change.name !== 'string' || !change.name.trim())
84
87
  errors.push({ code: 'EMPTY_NAME', message: `Change ${String(change.id)} has empty name`, path: `changes[${i}]` });
85
- if (typeof change.goal_id === 'number' && !goalIds.has(change.goal_id)) {
88
+ if ((typeof change.goal_id === 'number' || typeof change.goal_id === 'string') && !goalIds.has(change.goal_id)) {
86
89
  warnings.push({ code: 'BROKEN_REF', message: `Change ${String(change.id)} references missing goal ${change.goal_id}`, path: `changes[${i}].goal_id` });
87
90
  }
88
91
  const aids = Array.isArray(change.activity_ids) ? change.activity_ids : [];
89
92
  for (const aid of aids) {
90
- if (typeof aid === 'number' && !activityIds.has(aid)) {
93
+ if ((typeof aid === 'number' || typeof aid === 'string') && !activityIds.has(aid)) {
91
94
  warnings.push({ code: 'BROKEN_REF', message: `Change ${String(change.id)} references missing activity ${aid}`, path: `changes[${i}].activity_ids` });
92
95
  }
93
96
  }
@@ -99,8 +102,8 @@ export function validateFGCADoc(input) {
99
102
  continue;
100
103
  }
101
104
  const activity = a;
102
- if (typeof activity.id !== 'number')
103
- errors.push({ code: 'SCHEMA_INVALID', message: 'activity id must be a number', path: `activities[${i}]` });
105
+ if (typeof activity.id !== 'number' && typeof activity.id !== 'string')
106
+ errors.push({ code: 'SCHEMA_INVALID', message: 'activity id must be a number or string', path: `activities[${i}]` });
104
107
  if (typeof activity.name !== 'string' || !activity.name.trim())
105
108
  errors.push({ code: 'EMPTY_NAME', message: `Activity ${String(activity.id)} has empty name`, path: `activities[${i}]` });
106
109
  }
@@ -1,4 +1,4 @@
1
- export type { Goal, GoalType, GoalTree, Factor, ImpactType, ValidationResult, ValidationError, ValidationWarning, MutationResult, LayoutOptions, LaidOutNode, LaidOutEdge, GoalTreeLayout, } from './types.js';
1
+ export type { Goal, GoalType, GoalTree, ImpactType, ValidationResult, ValidationError, ValidationWarning, MutationResult, LayoutOptions, LaidOutNode, LaidOutEdge, GoalTreeLayout, } from './types.js';
2
2
  export { validateGoalTree } from './validate.js';
3
3
  export { parseCanonicalGoals } from './parse-canonical.js';
4
4
  export type { CanonicalGoalsResult } from './parse-canonical.js';
package/dist/index.d.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  export * from "./activities/index";
2
2
  export * from "./activity-card/index";
3
+ export * from "./actor/index";
3
4
  export * from "./geometry";
4
5
  export * from "./applications/index";
5
6
  export * from "./assertion/index";
6
7
  export * from "./blocks/index";
7
8
  export * from "./capability-map/index";
9
+ export * from "./change/index";
8
10
  export * from "./compliance/index";
9
11
  export * from "./compliance-matrix/index";
10
12
  export * from "./confidence/index";
13
+ export * from "./factor/index";
11
14
  export * from "./fgca/index";
12
15
  export * from "./goals/index";
13
16
  export * from "./process-blueprint/index";
@@ -16,6 +19,8 @@ export * from "./products/index";
16
19
  export * from "./repo-validate/index";
17
20
  export * from "./requirement/index";
18
21
  export * from "./scenarios/index";
22
+ export * from "./stakeholder/index";
23
+ export * from "./target-state/index";
19
24
  export { SCHEMA_VERSION } from "./schema-version";
20
25
  export * from "./theme/index";
21
26
  export * from "./typed-id";
package/dist/index.js CHANGED
@@ -1,13 +1,16 @@
1
1
  export * from "./activities/index";
2
2
  export * from "./activity-card/index";
3
+ export * from "./actor/index";
3
4
  export * from "./geometry";
4
5
  export * from "./applications/index";
5
6
  export * from "./assertion/index";
6
7
  export * from "./blocks/index";
7
8
  export * from "./capability-map/index";
9
+ export * from "./change/index";
8
10
  export * from "./compliance/index";
9
11
  export * from "./compliance-matrix/index";
10
12
  export * from "./confidence/index";
13
+ export * from "./factor/index";
11
14
  export * from "./fgca/index";
12
15
  export * from "./goals/index";
13
16
  export * from "./process-blueprint/index";
@@ -16,6 +19,8 @@ export * from "./products/index";
16
19
  export * from "./repo-validate/index";
17
20
  export * from "./requirement/index";
18
21
  export * from "./scenarios/index";
22
+ export * from "./stakeholder/index";
23
+ export * from "./target-state/index";
19
24
  export { SCHEMA_VERSION } from "./schema-version";
20
25
  export * from "./theme/index";
21
26
  export * from "./typed-id";
@@ -156,4 +156,41 @@ describe('layoutProcessBlueprint', () => {
156
156
  expect(layout.stageColumnWidth).toBe(300);
157
157
  expect(layout.stageHeaders[1].x).toBe(200 + 300);
158
158
  });
159
+ describe('visibleAspects', () => {
160
+ const FILE_WITH_ALL = build({
161
+ stages: [{ id: 'STAGE-1', name: 'A', goal: 'g', result: 'r' }],
162
+ systems: [{ name: 'OMS', stages: ['STAGE-1'] }],
163
+ actors: [{ name: 'Ops', stages: ['STAGE-1'] }],
164
+ equipment: [{ name: 'Printer', stages: ['STAGE-1'] }],
165
+ });
166
+ it('shows all categories when visibleAspects is not set', () => {
167
+ const layout = layoutProcessBlueprint(FILE_WITH_ALL);
168
+ expect(layout.aspectRows.map(r => r.category)).toEqual(expect.arrayContaining(['systems', 'actors', 'equipment']));
169
+ expect(layout.aspectRows).toHaveLength(3);
170
+ });
171
+ it('limits rows to those in visibleAspects', () => {
172
+ const layout = layoutProcessBlueprint(FILE_WITH_ALL, {
173
+ visibleAspects: ['systems'],
174
+ });
175
+ expect(layout.aspectRows).toHaveLength(1);
176
+ expect(layout.aspectRows[0].category).toBe('systems');
177
+ });
178
+ it('suppresses all aspect rows when visibleAspects is empty', () => {
179
+ const layout = layoutProcessBlueprint(FILE_WITH_ALL, { visibleAspects: [] });
180
+ expect(layout.aspectRows).toHaveLength(0);
181
+ });
182
+ it('preserves the canonical ASPECT_CATEGORIES order within the filtered set', () => {
183
+ const layout = layoutProcessBlueprint(FILE_WITH_ALL, {
184
+ visibleAspects: ['equipment', 'systems'],
185
+ });
186
+ expect(layout.aspectRows.map(r => r.category)).toEqual(['systems', 'equipment']);
187
+ });
188
+ it('ignores categories in visibleAspects that have no data', () => {
189
+ const layout = layoutProcessBlueprint(FILE_WITH_ALL, {
190
+ visibleAspects: ['systems', 'information_entities'],
191
+ });
192
+ expect(layout.aspectRows).toHaveLength(1);
193
+ expect(layout.aspectRows[0].category).toBe('systems');
194
+ });
195
+ });
159
196
  });
@@ -1,4 +1,4 @@
1
- export type { AspectCategory, Stage, AspectEntry, LaneConfig, ProcessBlueprintHeader, ProcessBlueprintFile, ProcessBlueprintLayoutOptions, LegendCell, StageHeaderCell, StageTextCell, AspectPill, AspectRow, ProcessBlueprintLayout, ComplianceDecoration, ComplianceChip, ComplianceRow, ComplianceLaneConfig, ComplianceLaneAssertion, ComplianceLaneRequirement, ComplianceLaneInput, } from './types.js';
1
+ export type { AspectCategory, RowId, Stage, AspectEntry, LaneConfig, ProcessBlueprintHeader, ProcessBlueprintFile, ProcessBlueprintLayoutOptions, LegendCell, StageHeaderCell, StageTextCell, AspectPill, AspectRow, ProcessBlueprintLayout, ComplianceDecoration, ComplianceChip, ComplianceRow, ComplianceLaneConfig, ComplianceLaneAssertion, ComplianceLaneRequirement, ComplianceLaneInput, } from './types.js';
2
2
  export { validateProcessBlueprint } from './validate.js';
3
3
  export type { ValidationError as ProcessBlueprintValidationError, ValidationWarning as ProcessBlueprintValidationWarning, ValidationResult as ProcessBlueprintValidationResult, } from './validate.js';
4
4
  export { layoutProcessBlueprint } from './layout.js';
@@ -12,14 +12,19 @@ const DEFAULTS = {
12
12
  goalRowHeight: 56,
13
13
  resultRowHeight: 56,
14
14
  aspectRowMinHeight: 60,
15
- pillHeight: 28,
15
+ pillHeight: 40,
16
16
  pillGap: 4,
17
17
  cellPadding: 8,
18
- textLineHeight: 15,
19
- textCharWidth: 6.2,
18
+ // 17px gives comfortable breathing room between wrapped lines at typical
19
+ // webview font sizes (VS Code uses ~13–14px body, SVG text-secondary ≈ same).
20
+ textLineHeight: 17,
21
+ // 7.5px per char is a conservative estimate that causes wrap to trigger
22
+ // before text visually overflows the cell border.
23
+ textCharWidth: 7.5,
20
24
  cellTextPadX: 10,
21
25
  cellTextPadY: 10,
22
- maxTextLines: 6,
26
+ // No hard truncation: rows grow to fit all wrapped lines.
27
+ maxTextLines: 100,
23
28
  };
24
29
  function resolveOptions(options) {
25
30
  return { ...DEFAULTS, ...(options ?? {}) };
@@ -285,8 +290,21 @@ function deriveComplianceRow(stages, stageIndexById, input, opts, yStart) {
285
290
  export function layoutProcessBlueprint(file, options) {
286
291
  const opts = resolveOptions(options);
287
292
  const pb = file.process_blueprint;
288
- const stages = Array.isArray(pb?.stages) ? pb.stages : [];
293
+ // Filter stages by visibleStages if set
294
+ const allStages = Array.isArray(pb?.stages) ? pb.stages : [];
295
+ const stages = opts.visibleStages
296
+ ? allStages.filter(s => s?.id != null && opts.visibleStages.includes(s.id))
297
+ : allStages;
289
298
  const stageIndexById = buildStageIndex(stages);
299
+ // Row visibility from visibleRows
300
+ const visRows = opts.visibleRows;
301
+ const showGoal = !visRows || visRows.includes('goal');
302
+ const showResult = !visRows || visRows.includes('result');
303
+ const effectiveVisibleAspects = visRows
304
+ ? ASPECT_CATEGORIES.filter(c => visRows.includes(c))
305
+ : opts.visibleAspects;
306
+ const effectiveComplianceEnabled = opts.complianceLane?.enabled === true &&
307
+ (!visRows || visRows.includes('compliance'));
290
308
  // Stage headers
291
309
  const stageHeaders = stages.map((s, i) => ({
292
310
  stageIndex: i,
@@ -307,33 +325,40 @@ export function layoutProcessBlueprint(file, options) {
307
325
  };
308
326
  const goalLines = stages.map(s => wrap(s?.goal ?? ''));
309
327
  const resultLines = stages.map(s => wrap(s?.result ?? ''));
310
- const goalRowY = opts.stageHeaderHeight;
311
- const goalRowHeight = rowHeightFor(goalLines.map(l => l.length), opts.goalRowHeight);
312
- const resultRowY = goalRowY + goalRowHeight;
313
- const resultRowHeight = rowHeightFor(resultLines.map(l => l.length), opts.resultRowHeight);
314
- const goalCells = stages.map((s, i) => ({
315
- stageIndex: i,
316
- text: s?.goal ?? '',
317
- lines: goalLines[i],
318
- x: opts.legendColumnWidth + i * opts.stageColumnWidth,
319
- y: goalRowY,
320
- width: opts.stageColumnWidth,
321
- height: goalRowHeight,
322
- }));
323
- const resultCells = stages.map((s, i) => ({
324
- stageIndex: i,
325
- text: s?.result ?? '',
326
- lines: resultLines[i],
327
- x: opts.legendColumnWidth + i * opts.stageColumnWidth,
328
- y: resultRowY,
329
- width: opts.stageColumnWidth,
330
- height: resultRowHeight,
331
- }));
332
- const aspectsStartY = resultRowY + resultRowHeight;
328
+ let cursorY = opts.stageHeaderHeight;
329
+ let goalRowY = 0, goalRowHeight = 0;
330
+ let resultRowY = 0, resultRowHeight = 0;
331
+ const goalCells = [];
332
+ const resultCells = [];
333
+ if (showGoal) {
334
+ goalRowY = cursorY;
335
+ goalRowHeight = rowHeightFor(goalLines.map(l => l.length), opts.goalRowHeight);
336
+ goalCells.push(...stages.map((s, i) => ({
337
+ stageIndex: i, text: s?.goal ?? '', lines: goalLines[i],
338
+ x: opts.legendColumnWidth + i * opts.stageColumnWidth, y: goalRowY,
339
+ width: opts.stageColumnWidth, height: goalRowHeight,
340
+ })));
341
+ cursorY += goalRowHeight;
342
+ }
343
+ if (showResult) {
344
+ resultRowY = cursorY;
345
+ resultRowHeight = rowHeightFor(resultLines.map(l => l.length), opts.resultRowHeight);
346
+ resultCells.push(...stages.map((s, i) => ({
347
+ stageIndex: i, text: s?.result ?? '', lines: resultLines[i],
348
+ x: opts.legendColumnWidth + i * opts.stageColumnWidth, y: resultRowY,
349
+ width: opts.stageColumnWidth, height: resultRowHeight,
350
+ })));
351
+ cursorY += resultRowHeight;
352
+ }
353
+ const aspectsStartY = cursorY;
333
354
  // Aspect rows: only categories with at least one entry, in fixed order.
355
+ // When effectiveVisibleAspects is set, skip categories not in the list.
356
+ const aspectCategoriesToRender = effectiveVisibleAspects !== undefined
357
+ ? ASPECT_CATEGORIES.filter(c => effectiveVisibleAspects.includes(c))
358
+ : ASPECT_CATEGORIES;
334
359
  const aspectRows = [];
335
360
  let aspectCursorY = aspectsStartY;
336
- for (const category of ASPECT_CATEGORIES) {
361
+ for (const category of aspectCategoriesToRender) {
337
362
  const arr = pb?.[category];
338
363
  if (!Array.isArray(arr) || arr.length === 0)
339
364
  continue;
@@ -354,6 +379,13 @@ export function layoutProcessBlueprint(file, options) {
354
379
  const x = opts.legendColumnWidth + p.startStageIndex * opts.stageColumnWidth + opts.cellPadding;
355
380
  const width = (p.endStageIndex - p.startStageIndex + 1) * opts.stageColumnWidth - 2 * opts.cellPadding;
356
381
  const y = aspectCursorY + opts.cellPadding + slot[i] * (opts.pillHeight + opts.pillGap);
382
+ const pillMaxChars = Math.max(4, Math.floor((width - 2 * opts.cellPadding) / opts.textCharWidth));
383
+ const nameWrapped = wrapText(p.name, pillMaxChars, 2);
384
+ // Show id as second line only when the name fits on one line; otherwise
385
+ // use both lines for the name so it isn't truncated.
386
+ const lines = p.id && nameWrapped.length <= 1
387
+ ? [...nameWrapped, p.id].slice(0, 2)
388
+ : nameWrapped;
357
389
  return {
358
390
  category: p.category,
359
391
  entryIndex: p.entryIndex,
@@ -365,6 +397,7 @@ export function layoutProcessBlueprint(file, options) {
365
397
  y,
366
398
  width,
367
399
  height: opts.pillHeight,
400
+ lines,
368
401
  };
369
402
  });
370
403
  aspectRows.push({
@@ -377,7 +410,7 @@ export function layoutProcessBlueprint(file, options) {
377
410
  }
378
411
  // Compliance lane — derived from assertions/requirements, rendered after aspect rows.
379
412
  let complianceRow;
380
- if (opts.complianceLane?.enabled && opts.complianceInput) {
413
+ if (effectiveComplianceEnabled && opts.complianceInput) {
381
414
  complianceRow = deriveComplianceRow(stages, stageIndexById, opts.complianceInput, opts, aspectCursorY);
382
415
  if (complianceRow) {
383
416
  aspectCursorY += complianceRow.height;
@@ -385,8 +418,8 @@ export function layoutProcessBlueprint(file, options) {
385
418
  }
386
419
  // Legend (left column labels): one entry per row.
387
420
  const legend = [
388
- { kind: 'goal', label: 'Goal', y: goalRowY, height: goalRowHeight },
389
- { kind: 'result', label: 'Result', y: resultRowY, height: resultRowHeight },
421
+ ...(showGoal ? [{ kind: 'goal', label: 'Goal', y: goalRowY, height: goalRowHeight }] : []),
422
+ ...(showResult ? [{ kind: 'result', label: 'Result', y: resultRowY, height: resultRowHeight }] : []),
390
423
  ...aspectRows.map(row => ({
391
424
  kind: 'aspect',
392
425
  category: row.category,
@@ -394,9 +427,7 @@ export function layoutProcessBlueprint(file, options) {
394
427
  y: row.y,
395
428
  height: row.height,
396
429
  })),
397
- ...(complianceRow
398
- ? [{ kind: 'compliance', label: 'Compliance', y: complianceRow.y, height: complianceRow.height }]
399
- : []),
430
+ ...(complianceRow ? [{ kind: 'compliance', label: 'Compliance', y: complianceRow.y, height: complianceRow.height }] : []),
400
431
  ];
401
432
  const totalWidth = opts.legendColumnWidth + stages.length * opts.stageColumnWidth;
402
433
  const totalHeight = aspectCursorY;
@@ -1,4 +1,5 @@
1
1
  export type AspectCategory = 'systems' | 'actors' | 'equipment' | 'information_entities';
2
+ export type RowId = 'goal' | 'result' | 'systems' | 'actors' | 'equipment' | 'information_entities' | 'compliance';
2
3
  /**
3
4
  * One of the three orthogonal decoration signals that can appear on a compliance
4
5
  * law chip (ADR 2026-06-09-compliance-impact-as-blueprint-lane §3):
@@ -24,7 +25,7 @@ export interface ComplianceLaneAssertion {
24
25
  /** Requirement ID this assertion is about. */
25
26
  about: string;
26
27
  /** Compliance realisation status. */
27
- status: 'compliant' | 'partial' | 'non_compliant' | 'under_review' | 'n_a';
28
+ status: 'compliant' | 'partial' | 'non_compliant' | 'under_review' | 'pending_owner' | 'n_a';
28
29
  /**
29
30
  * Typed IDs of stages / process steps where the requirement is realised.
30
31
  * When empty/absent, the assertion covers the entire subject, not a specific stage.
@@ -106,7 +107,22 @@ export interface LaneConfig {
106
107
  compliance_filter?: {
107
108
  /** ISO jurisdiction codes; empty array means all jurisdictions. */
108
109
  jurisdictions?: string[];
110
+ /**
111
+ * Per-stage map of law IDs known from the previous generated snapshot.
112
+ * Key: stage ID; Value: array of law IDs present in that stage's previous report.
113
+ * Laws absent from the previous snapshot receive the `new` decoration.
114
+ * When absent, every law chip is treated as new.
115
+ */
116
+ previous_snapshot?: Record<string, string[]>;
109
117
  };
118
+ /**
119
+ * Lanes to show; controls which aspect rows and the compliance lane are rendered.
120
+ * Valid values: `"systems"` | `"actors"` | `"equipment"` | `"information_entities"` | `"compliance"`.
121
+ * When absent, all lanes with data are shown (current default behaviour).
122
+ * Named report config — committed, versioned. Per-user overrides live in
123
+ * `.transitrix/display-preferences/process-blueprint.json` (gitignored, never committed).
124
+ */
125
+ visible_lanes?: string[];
110
126
  }
111
127
  export interface ProcessBlueprintHeader {
112
128
  id: string;
@@ -155,6 +171,23 @@ export interface ProcessBlueprintLayoutOptions {
155
171
  complianceLane?: ComplianceLaneConfig;
156
172
  /** Assertion + requirement data for the compliance lane derivation. */
157
173
  complianceInput?: ComplianceLaneInput;
174
+ /**
175
+ * Restrict which aspect-category rows are rendered.
176
+ * When absent, all categories that have at least one entry are shown.
177
+ * Pass an empty array to suppress all aspect rows.
178
+ */
179
+ visibleAspects?: AspectCategory[];
180
+ /**
181
+ * Restrict which rows are rendered. When absent, all rows with data are shown.
182
+ * When set, takes precedence over `visibleAspects` for aspect categories and
183
+ * overrides `complianceLane.enabled` for the compliance row.
184
+ */
185
+ visibleRows?: RowId[];
186
+ /**
187
+ * Restrict which stages (columns) are rendered by their stage ID.
188
+ * When absent, all stages are shown.
189
+ */
190
+ visibleStages?: string[];
158
191
  }
159
192
  import type { LayoutBounds } from '../geometry.js';
160
193
  export type { LayoutBounds };
@@ -195,6 +228,8 @@ export interface AspectPill {
195
228
  y: number;
196
229
  width: number;
197
230
  height: number;
231
+ /** Word-wrapped lines of `name`, pre-fitted to the pill width by the layout. */
232
+ lines: string[];
198
233
  }
199
234
  export interface AspectRow {
200
235
  category: AspectCategory;
@@ -1,2 +1,2 @@
1
- export type { ScenarioStatus, FactorRelevance, FactorView, GoalRef, CapabilityRef, ActivityRef, ProductRef, ProcessRef, ApplicationRef, ScenarioHeader, ScenarioFile, } from './types.js';
1
+ export type { ScenarioStatus, DriverRelevance, DriverView, GoalRef, CapabilityRef, ActivityRef, ProductRef, ProcessRef, ApplicationRef, ScenarioHeader, ScenarioFile, } from './types.js';
2
2
  export { validateScenario } from './validate.js';