@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
@@ -1,102 +1,102 @@
1
- // Compliance matrix model (vkgeorgia/strategy#84 Phase 2).
2
- //
3
- // The matrix is Products × Requirements. Each cell is the status of the
4
- // (Product, Requirement) ASSERTION when one exists, or a gap when none does.
5
- // Pure data — the layout is computed by `build.ts`; the Studio preview renders
6
- // it. Non-product-subject assertions (CAPABILITY / PROCESS) belong to the
7
- // single-product / single-law views (Phase 3) and are ignored here.
8
-
9
- import type { AssertionStatus } from '../assertion/types.js';
10
-
11
- /** A row of the matrix — a discovered PRODUCT element. */
12
- export interface MatrixProduct {
13
- id: string;
14
- name: string;
15
- /** True when the product was discovered only as an assertion subject (no
16
- * product element file resolves it) — a dangling subject reference. */
17
- unresolved?: boolean;
18
- }
19
-
20
- /** A column of the matrix — a discovered REQUIREMENT. */
21
- export interface MatrixRequirement {
22
- id: string;
23
- name: string;
24
- /** Organisation-defined priority (high | medium | low), used by the filter. */
25
- severity?: string;
26
- /** Typed IDs of the codex sources this requirement derives from (verbatim
27
- * from `derived_from`). Carried so the renderer can surface provenance and
28
- * resolve jurisdictions without re-scanning. */
29
- derived_from?: string[];
30
- /** Jurisdictions resolved by walking `derived_from` → codex artefacts and
31
- * collecting their `jurisdiction` (Codex §1.1). Unique, sorted. Empty when
32
- * no codex source resolves with a jurisdiction (internal-only requirements,
33
- * or codex artefacts the scan did not find / has no jurisdiction). The
34
- * toolbar jurisdiction filter (F16) keys on this set. */
35
- jurisdictions?: string[];
36
- }
37
-
38
- /** A codex source document the matrix uses to resolve `Requirement.jurisdictions`. */
39
- export interface MatrixCodexDoc {
40
- id: string;
41
- jurisdiction?: string;
42
- }
43
-
44
- /** The assertion fields the matrix needs (a projection of the full Assertion). */
45
- export interface MatrixAssertionRef {
46
- id: string;
47
- about: string;
48
- subject: string;
49
- status: AssertionStatus;
50
- assessed_at?: string;
51
- next_review_at?: string;
52
- }
53
-
54
- /** One grid cell. `status === undefined` is a gap (no assertion for the pair). */
55
- export interface MatrixCell {
56
- productId: string;
57
- requirementId: string;
58
- /** The assertion filling this cell, when one exists. */
59
- assertionId?: string;
60
- status?: AssertionStatus;
61
- assessed_at?: string;
62
- next_review_at?: string;
63
- }
64
-
65
- export interface ComplianceMatrix {
66
- /** Rows, sorted by id. */
67
- products: MatrixProduct[];
68
- /** Columns, sorted by id. */
69
- requirements: MatrixRequirement[];
70
- /** `cells[rowIndex][colIndex]`, aligned to `products` × `requirements`. */
71
- cells: MatrixCell[][];
72
- /** Counts for the summary strip. */
73
- summary: {
74
- products: number;
75
- requirements: number;
76
- assertions: number;
77
- /** Cells with no assertion (compliance gaps). */
78
- gaps: number;
79
- };
80
- }
81
-
82
- export interface ComplianceMatrixInput {
83
- products: MatrixProduct[];
84
- requirements: MatrixRequirement[];
85
- assertions: MatrixAssertionRef[];
86
- /** Codex source documents — used to resolve each Requirement's jurisdictions
87
- * by walking `derived_from`. Optional: when omitted the builder still works
88
- * and every requirement's `jurisdictions` is left empty. */
89
- codex?: MatrixCodexDoc[];
90
- }
91
-
92
- /** Toolbar filter — empty/omitted fields mean "no filter on that dimension". */
93
- export interface MatrixFilter {
94
- /** Keep only requirement columns whose severity is in this set. */
95
- severities?: string[];
96
- /** Keep only the cell status badges in this set; others render as filtered. */
97
- statuses?: AssertionStatus[];
98
- /** Keep only requirement columns whose resolved jurisdictions intersect this
99
- * set. Requirements with no resolved jurisdiction are filtered out when this
100
- * is non-empty (F16, epic #84). */
101
- jurisdictions?: string[];
102
- }
1
+ // Compliance matrix model (vkgeorgia/strategy#84 Phase 2).
2
+ //
3
+ // The matrix is Products × Requirements. Each cell is the status of the
4
+ // (Product, Requirement) ASSERTION when one exists, or a gap when none does.
5
+ // Pure data — the layout is computed by `build.ts`; the Studio preview renders
6
+ // it. Non-product-subject assertions (CAPABILITY / PROCESS) belong to the
7
+ // single-product / single-law views (Phase 3) and are ignored here.
8
+
9
+ import type { AssertionStatus } from '../assertion/types.js';
10
+
11
+ /** A row of the matrix — a discovered PRODUCT element. */
12
+ export interface MatrixProduct {
13
+ id: string;
14
+ name: string;
15
+ /** True when the product was discovered only as an assertion subject (no
16
+ * product element file resolves it) — a dangling subject reference. */
17
+ unresolved?: boolean;
18
+ }
19
+
20
+ /** A column of the matrix — a discovered REQUIREMENT. */
21
+ export interface MatrixRequirement {
22
+ id: string;
23
+ name: string;
24
+ /** Organisation-defined priority (high | medium | low), used by the filter. */
25
+ severity?: string;
26
+ /** Typed IDs of the codex sources this requirement derives from (verbatim
27
+ * from `derived_from`). Carried so the renderer can surface provenance and
28
+ * resolve jurisdictions without re-scanning. */
29
+ derived_from?: string[];
30
+ /** Jurisdictions resolved by walking `derived_from` → codex artefacts and
31
+ * collecting their `jurisdiction` (Codex §1.1). Unique, sorted. Empty when
32
+ * no codex source resolves with a jurisdiction (internal-only requirements,
33
+ * or codex artefacts the scan did not find / has no jurisdiction). The
34
+ * toolbar jurisdiction filter (F16) keys on this set. */
35
+ jurisdictions?: string[];
36
+ }
37
+
38
+ /** A codex source document the matrix uses to resolve `Requirement.jurisdictions`. */
39
+ export interface MatrixCodexDoc {
40
+ id: string;
41
+ jurisdiction?: string;
42
+ }
43
+
44
+ /** The assertion fields the matrix needs (a projection of the full Assertion). */
45
+ export interface MatrixAssertionRef {
46
+ id: string;
47
+ about: string;
48
+ subject: string;
49
+ status: AssertionStatus;
50
+ assessed_at?: string;
51
+ next_review_at?: string;
52
+ }
53
+
54
+ /** One grid cell. `status === undefined` is a gap (no assertion for the pair). */
55
+ export interface MatrixCell {
56
+ productId: string;
57
+ requirementId: string;
58
+ /** The assertion filling this cell, when one exists. */
59
+ assertionId?: string;
60
+ status?: AssertionStatus;
61
+ assessed_at?: string;
62
+ next_review_at?: string;
63
+ }
64
+
65
+ export interface ComplianceMatrix {
66
+ /** Rows, sorted by id. */
67
+ products: MatrixProduct[];
68
+ /** Columns, sorted by id. */
69
+ requirements: MatrixRequirement[];
70
+ /** `cells[rowIndex][colIndex]`, aligned to `products` × `requirements`. */
71
+ cells: MatrixCell[][];
72
+ /** Counts for the summary strip. */
73
+ summary: {
74
+ products: number;
75
+ requirements: number;
76
+ assertions: number;
77
+ /** Cells with no assertion (compliance gaps). */
78
+ gaps: number;
79
+ };
80
+ }
81
+
82
+ export interface ComplianceMatrixInput {
83
+ products: MatrixProduct[];
84
+ requirements: MatrixRequirement[];
85
+ assertions: MatrixAssertionRef[];
86
+ /** Codex source documents — used to resolve each Requirement's jurisdictions
87
+ * by walking `derived_from`. Optional: when omitted the builder still works
88
+ * and every requirement's `jurisdictions` is left empty. */
89
+ codex?: MatrixCodexDoc[];
90
+ }
91
+
92
+ /** Toolbar filter — empty/omitted fields mean "no filter on that dimension". */
93
+ export interface MatrixFilter {
94
+ /** Keep only requirement columns whose severity is in this set. */
95
+ severities?: string[];
96
+ /** Keep only the cell status badges in this set; others render as filtered. */
97
+ statuses?: AssertionStatus[];
98
+ /** Keep only requirement columns whose resolved jurisdictions intersect this
99
+ * set. Requirements with no resolved jurisdiction are filtered out when this
100
+ * is non-empty (F16, epic #84). */
101
+ jurisdictions?: string[];
102
+ }
package/src/edge-path.ts CHANGED
@@ -1,44 +1,50 @@
1
- // Shared edge geometry for the static notation previews (Goals, FGCA, FGA,
2
- // Activities). All four render dependency/relationship edges as a single cubic
3
- // Bézier with horizontal control handles: each control point shares its
4
- // endpoint's Y, so the tangent is horizontal at both ends and the marker-end
5
- // arrow reads as perpendicular to the node's vertical edge.
6
- //
7
- // Pulling the path math here (rather than duplicating it inline in each
8
- // preview) makes the configurable-curvature behaviour (vkgeorgia/strategy#76)
9
- // unit-testable — the extension has no test harness.
10
-
11
- /**
12
- * Base handle length floor + span factors. The handle grows with both the
13
- * horizontal and vertical span so the curve stays visibly horizontal long
14
- * enough for the arrowhead to sit flush against the line.
15
- */
16
- export const EDGE_MIN_HANDLE = 64;
17
- const DX_FACTOR = 0.5;
18
- const DY_FACTOR = 0.8;
19
-
20
- /** Multiplier applied to the base handle length. 1 = historical appearance. */
21
- export const DEFAULT_EDGE_CURVATURE = 1;
22
-
23
- /**
24
- * Builds the SVG `d` for a horizontal-tangent cubic Bézier from (sx,sy) to
25
- * (tx,ty).
26
- *
27
- * `curvature` scales the control-handle length:
28
- * - 0 → control points collapse onto the endpoints ⇒ a straight line.
29
- * - 1 → the historical curve (no visual change from before #76).
30
- * - >1 → progressively stronger arc.
31
- */
32
- export function horizontalCubicEdgePath(
33
- sx: number,
34
- sy: number,
35
- tx: number,
36
- ty: number,
37
- curvature: number = DEFAULT_EDGE_CURVATURE,
38
- ): string {
39
- const dx = tx - sx;
40
- const dy = ty - sy;
41
- const baseHandle = Math.max(EDGE_MIN_HANDLE, Math.abs(dx) * DX_FACTOR, Math.abs(dy) * DY_FACTOR);
42
- const handle = baseHandle * curvature;
43
- return `M${sx},${sy} C${sx + handle},${sy} ${tx - handle},${ty} ${tx},${ty}`;
44
- }
1
+ // Shared edge geometry for the static notation previews (Goals, FGCA, FGA,
2
+ // Activities). All four render dependency/relationship edges as a single cubic
3
+ // Bézier with horizontal control handles: each control point shares its
4
+ // endpoint's Y, so the tangent is horizontal at both ends and the marker-end
5
+ // arrow reads as perpendicular to the node's vertical edge.
6
+ //
7
+ // Pulling the path math here (rather than duplicating it inline in each
8
+ // preview) makes the configurable-curvature behaviour (vkgeorgia/strategy#76)
9
+ // unit-testable — the extension has no test harness.
10
+
11
+ /**
12
+ * Base handle length floor + span factors. The handle grows with both the
13
+ * horizontal and vertical span so the curve stays visibly horizontal long
14
+ * enough for the arrowhead to sit flush against the line.
15
+ */
16
+ export const EDGE_MIN_HANDLE = 64;
17
+ const DX_FACTOR = 0.5;
18
+ const DY_FACTOR = 0.8;
19
+
20
+ /** Multiplier applied to the base handle length. 1 = historical appearance. */
21
+ export const DEFAULT_EDGE_CURVATURE = 1;
22
+
23
+ /**
24
+ * Builds the SVG `d` for a horizontal-tangent cubic Bézier from (sx,sy) to
25
+ * (tx,ty).
26
+ *
27
+ * `curvature` scales the exit control-handle (departure from source).
28
+ * `entryCurvature` scales the entry control-handle (arrival at target);
29
+ * defaults to `curvature` when omitted so callers that pass one value get
30
+ * symmetric handles (the historical behaviour).
31
+ *
32
+ * - 0 → handle collapses onto its endpoint ⇒ straight at that end.
33
+ * - 1 → the historical curve (no visual change from before #76).
34
+ * - >1 → progressively stronger arc at that end.
35
+ */
36
+ export function horizontalCubicEdgePath(
37
+ sx: number,
38
+ sy: number,
39
+ tx: number,
40
+ ty: number,
41
+ curvature: number = DEFAULT_EDGE_CURVATURE,
42
+ entryCurvature?: number,
43
+ ): string {
44
+ const dx = tx - sx;
45
+ const dy = ty - sy;
46
+ const baseHandle = Math.max(EDGE_MIN_HANDLE, Math.abs(dx) * DX_FACTOR, Math.abs(dy) * DY_FACTOR);
47
+ const exitHandle = baseHandle * curvature;
48
+ const entryHandle = baseHandle * (entryCurvature ?? curvature);
49
+ return `M${sx},${sy} C${sx + exitHandle},${sy} ${tx - entryHandle},${ty} ${tx},${ty}`;
50
+ }
@@ -1,11 +1,12 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { validateFactor } from '../validate.js';
3
+ import type { CanonCatalog } from '../../typed-id.js';
3
4
 
4
- function valid(): Record<string, unknown> {
5
+ function validExternal(): Record<string, unknown> {
5
6
  return {
6
- notation: 'factor',
7
+ notation: 'driver',
7
8
  id: 'FACTOR-EU-REG-1',
8
- name: 'EU regulatory window for market entry',
9
+ name: 'EU regulatory window',
9
10
  type: 'external',
10
11
  category: 'legal',
11
12
  description: 'Standing external driver — the EU regulatory regime.',
@@ -19,80 +20,114 @@ function valid(): Record<string, unknown> {
19
20
  };
20
21
  }
21
22
 
22
- const codes = (input: unknown): string[] => validateFactor(input).errors.map(e => e.code);
23
- const warns = (input: unknown): string[] => validateFactor(input).warnings.map(w => w.code);
23
+ function validInternal(): Record<string, unknown> {
24
+ return {
25
+ notation: 'driver',
26
+ id: 'FACTOR-COMP-1',
27
+ name: 'Support response time',
28
+ type: 'internal',
29
+ description: 'Standing internal driver.',
30
+ zone: 'canon',
31
+ admitted_at: '2026-05-29',
32
+ admitted_by: 'v.korobeinikov',
33
+ gate_checks: { uniqueness: 'pass', consistency: 'pass', completeness: 'pass' },
34
+ valid_from: '2026-05-26',
35
+ valid_to: null,
36
+ };
37
+ }
38
+
39
+ const codes = (input: unknown, opts?: Parameters<typeof validateFactor>[1]): string[] =>
40
+ validateFactor(input, opts).errors.map(e => e.code);
24
41
 
25
42
  describe('validateFactor — positive', () => {
26
- it('accepts the worked-example FACTOR-EU-REG-1', () => {
27
- const r = validateFactor(valid());
43
+ it('accepts a well-formed external PESTLE factor', () => {
44
+ const r = validateFactor(validExternal());
28
45
  expect(r.valid, JSON.stringify(r.errors)).toBe(true);
29
- expect(r.errors).toHaveLength(0);
30
46
  });
31
47
 
32
- it('accepts a minimal factor (no type/category/references)', () => {
33
- const r = valid();
34
- delete r.type;
35
- delete r.category;
36
- delete r.references_constraint;
37
- expect(validateFactor(r).valid).toBe(true);
48
+ it('accepts a well-formed internal factor (no PESTLE category)', () => {
49
+ expect(validateFactor(validInternal()).valid).toBe(true);
38
50
  });
39
- });
40
51
 
41
- describe('validateFactor — FACTOR-001 (envelope / shape)', () => {
42
- it('flags a non-object', () => {
43
- expect(codes(null)).toEqual(['FACTOR-001']);
44
- expect(codes(['x'])).toEqual(['FACTOR-001']);
52
+ it('accepts a minimal factor with no optional fields', () => {
53
+ const f = validInternal();
54
+ delete f.type;
55
+ delete f.description;
56
+ expect(validateFactor(f).valid).toBe(true);
45
57
  });
58
+ });
46
59
 
47
- it('flags a wrong notation tag', () => {
48
- expect(codes({ ...valid(), notation: 'driver' })).toContain('FACTOR-001');
60
+ describe('validateFactor — FACTOR-001 (shape / id grammar)', () => {
61
+ it('flags a missing required envelope field', () => {
62
+ const f = validExternal();
63
+ delete f.admitted_by;
64
+ expect(codes(f)).toContain('FACTOR-001');
49
65
  });
50
66
 
51
- it('flags an id with the wrong TYPE prefix', () => {
52
- expect(codes({ ...valid(), id: 'GOAL-EU-1' })).toContain('FACTOR-001');
67
+ it('flags an id that violates the grammar', () => {
68
+ expect(codes({ ...validExternal(), id: 'FACTOR-EU-REG-001' })).toContain('FACTOR-001');
69
+ expect(codes({ ...validExternal(), id: 'FAC-1' })).toContain('FACTOR-001');
70
+ expect(codes({ ...validExternal(), id: 'factor-1' })).toContain('FACTOR-001');
53
71
  });
54
72
 
55
- it('flags an id with a leading-zero terminal', () => {
56
- expect(codes({ ...valid(), id: 'FACTOR-EU-REG-01' })).toContain('FACTOR-001');
73
+ it('flags a wrong notation tag and a non-canon zone', () => {
74
+ expect(codes({ ...validExternal(), notation: 'factor' })).toContain('FACTOR-001');
75
+ expect(codes({ ...validExternal(), zone: 'sandbox' })).toContain('FACTOR-001');
57
76
  });
58
77
 
59
78
  it('flags a missing valid_to key (distinct from a null value)', () => {
60
- const r = valid();
61
- delete r.valid_to;
62
- expect(codes(r)).toContain('FACTOR-001');
63
- expect(validateFactor({ ...valid(), valid_to: null }).valid).toBe(true);
79
+ const f = validExternal();
80
+ delete f.valid_to;
81
+ expect(codes(f)).toContain('FACTOR-001');
64
82
  });
65
83
 
66
- it('flags references_constraint entries that are not CONSTRAINT typed ids', () => {
67
- expect(codes({ ...valid(), references_constraint: ['GOAL-EU-1'] })).toContain('FACTOR-001');
68
- expect(codes({ ...valid(), references_constraint: 'CONSTRAINT-X-1' })).toContain('FACTOR-001');
84
+ it('rejects a non-object', () => {
85
+ expect(codes(null)).toEqual(['FACTOR-001']);
86
+ expect(codes(['a'])).toEqual(['FACTOR-001']);
69
87
  });
70
88
  });
71
89
 
72
90
  describe('validateFactor — FACTOR-002 (type enum)', () => {
73
- it('flags a type outside external/internal', () => {
74
- expect(codes({ ...valid(), type: 'driver' })).toContain('FACTOR-002');
91
+ it('flags a type value outside {external, internal}', () => {
92
+ expect(codes({ ...validExternal(), type: 'driver' })).toContain('FACTOR-002');
93
+ });
94
+ });
95
+
96
+ describe('validateFactor — FACTOR-003 (PESTLE category)', () => {
97
+ it('flags a category outside PESTLE', () => {
98
+ expect(codes({ ...validExternal(), category: 'cosmic' })).toContain('FACTOR-003');
75
99
  });
76
100
 
77
- it('accepts each permitted type', () => {
78
- for (const t of ['external', 'internal']) {
79
- expect(codes({ ...valid(), type: t, category: undefined })).not.toContain('FACTOR-002');
101
+ it('flags PESTLE category on an internal factor', () => {
102
+ const f = validInternal();
103
+ f.category = 'legal';
104
+ expect(codes(f)).toContain('FACTOR-003');
105
+ });
106
+
107
+ it('accepts each permitted PESTLE category on an external factor', () => {
108
+ for (const cat of ['political', 'economic', 'social', 'technological', 'legal', 'environmental']) {
109
+ const f = validExternal();
110
+ f.category = cat;
111
+ expect(codes(f)).not.toContain('FACTOR-003');
80
112
  }
81
113
  });
82
114
  });
83
115
 
84
- describe('validateFactor — FACTOR-003 (PESTLE category)', () => {
85
- it('flags a category outside the PESTLE classes', () => {
86
- expect(codes({ ...valid(), category: 'cultural' })).toContain('FACTOR-003');
116
+ describe('validateFactor — FACTOR-004 (references_constraint)', () => {
117
+ it('flags a malformed references_constraint entry', () => {
118
+ expect(codes({ ...validExternal(), references_constraint: ['not an id'] })).toContain('FACTOR-004');
87
119
  });
88
120
 
89
- it('warns when category is set on an internal factor', () => {
90
- expect(warns({ ...valid(), type: 'internal', category: 'economic' })).toContain('FACTOR-003');
121
+ it('flags a references_constraint entry of the wrong TYPE', () => {
122
+ expect(codes({ ...validExternal(), references_constraint: ['GOAL-X-1'] })).toContain('FACTOR-004');
91
123
  });
92
124
 
93
- it('accepts each permitted PESTLE class', () => {
94
- for (const c of ['political', 'economic', 'social', 'technological', 'legal', 'environmental']) {
95
- expect(codes({ ...valid(), category: c })).not.toContain('FACTOR-003');
96
- }
125
+ it('flags an unresolved id when a catalog is supplied', () => {
126
+ const catalog: CanonCatalog = { typeOf: () => undefined };
127
+ expect(codes(validExternal(), { catalog })).toContain('FACTOR-004');
128
+ });
129
+
130
+ it('does not flag without a catalog for a well-formed CONSTRAINT id', () => {
131
+ expect(codes(validExternal())).not.toContain('FACTOR-004');
97
132
  });
98
133
  });
@@ -1,8 +1,4 @@
1
- // The `Factor` type is re-exported under the alias `FactorPrimitive` at the
2
- // package surface to avoid a name collision with the legacy FGCA-inline
3
- // `Factor` shape exported from `./goals/index` (a v0.x view shape with
4
- // numeric ids — distinct from this element primitive). Both types remain
5
- // importable from their module subpaths.
6
- export type { Factor as FactorPrimitive, FactorType, FactorCategory } from './types.js';
7
- export { FACTOR_TYPES, FACTOR_CATEGORIES } from './types.js';
1
+ export type { Factor, FactorType, FactorPestleCategory } from './types.js';
2
+ export { FACTOR_PESTLE_CATEGORIES } from './types.js';
8
3
  export { validateFactor } from './validate.js';
4
+ export type { FactorValidateOptions } from './validate.js';
@@ -1,41 +1,37 @@
1
- // FACTOR — motivation-layer driver primitive.
2
- // Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.1 + envelope §3.
1
+ // FACTOR — motivation-layer Driver (ArchiMate).
2
+ // Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.1.
3
3
 
4
4
  import type { GateChecks } from '../requirement/types.js';
5
5
 
6
- /** Optional subtype — internal/external organisation force. */
7
6
  export type FactorType = 'external' | 'internal';
8
7
 
9
- export const FACTOR_TYPES = ['external', 'internal'] as const;
10
-
11
- /** PESTLE sub-classification — external factors only. Open-ended in practice
12
- * but v1 fixes the six standard classes; an unknown category is flagged. */
13
- export type FactorCategory =
14
- | 'political'
15
- | 'economic'
16
- | 'social'
17
- | 'technological'
18
- | 'legal'
19
- | 'environmental';
20
-
21
- export const FACTOR_CATEGORIES = [
22
- 'political', 'economic', 'social', 'technological', 'legal', 'environmental',
8
+ /** PESTLE sub-classification — external factors only (§7.1). */
9
+ export const FACTOR_PESTLE_CATEGORIES = [
10
+ 'political',
11
+ 'economic',
12
+ 'social',
13
+ 'technological',
14
+ 'legal',
15
+ 'environmental',
23
16
  ] as const;
17
+ export type FactorPestleCategory = typeof FACTOR_PESTLE_CATEGORIES[number];
24
18
 
25
19
  export interface Factor {
26
- notation: 'factor';
20
+ notation: 'driver';
27
21
  id: string;
28
22
  name: string;
29
23
  type?: FactorType;
30
- category?: FactorCategory;
24
+ category?: FactorPestleCategory;
31
25
  description?: string;
32
26
  references_constraint?: string[];
33
27
 
28
+ // Admission record (CONTRACT.md §6).
34
29
  zone: 'canon';
35
30
  admitted_at: string;
36
31
  admitted_by: string;
37
32
  gate_checks: GateChecks;
38
33
 
34
+ // Primitive lifecycle (CONTRACT.md §7).
39
35
  valid_from: string;
40
36
  valid_to: string | null;
41
37
  }