@transitrix/diagrams 1.8.20 → 1.9.18

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 (176) hide show
  1. package/dist/activity-card/types.js +1 -1
  2. package/dist/agreement.d.ts +15 -0
  3. package/dist/agreement.js +61 -0
  4. package/dist/applications/index.d.ts +2 -0
  5. package/dist/applications/index.js +1 -0
  6. package/dist/applications/resolve-maturity.d.ts +16 -0
  7. package/dist/applications/resolve-maturity.js +57 -0
  8. package/dist/applications/validate.js +20 -0
  9. package/dist/capability-map/CapabilityCardNode.d.ts +1 -1
  10. package/dist/capability-map/CapabilityRootNode.d.ts +1 -1
  11. package/dist/capability-map/index.d.ts +2 -0
  12. package/dist/capability-map/index.js +1 -0
  13. package/dist/capability-map/resolve-maturity.d.ts +20 -0
  14. package/dist/capability-map/resolve-maturity.js +72 -0
  15. package/dist/capability-map/validate.js +1 -2
  16. package/dist/compliance/classify.d.ts +10 -1
  17. package/dist/compliance/classify.js +44 -2
  18. package/dist/compliance/confidence.js +1 -1
  19. package/dist/compliance/gap-report.d.ts +31 -1
  20. package/dist/compliance/gap-report.js +55 -3
  21. package/dist/compliance/html.d.ts +1 -1
  22. package/dist/compliance/html.js +15 -7
  23. package/dist/compliance/impact.js +1 -1
  24. package/dist/compliance/index.d.ts +3 -1
  25. package/dist/compliance/index.js +2 -0
  26. package/dist/compliance/markdown.js +26 -4
  27. package/dist/compliance/reverse-index.d.ts +6 -1
  28. package/dist/compliance/reverse-index.js +27 -3
  29. package/dist/compliance/trace.js +5 -1
  30. package/dist/compliance/types.d.ts +70 -0
  31. package/dist/compliance/types.js +1 -2
  32. package/dist/compliance/views.js +1 -1
  33. package/dist/compliance-matrix/types.d.ts +1 -1
  34. package/dist/compliance-matrix/types.js +1 -1
  35. package/dist/confidence/score.js +1 -1
  36. package/dist/constraint/validate.js +3 -0
  37. package/dist/edge-path.js +1 -1
  38. package/dist/factor/validate.js +2 -2
  39. package/dist/fgca/chain-table.js +1 -1
  40. package/dist/fgca/nodeTypes.d.ts +4 -4
  41. package/dist/fgca/nodes/FGCAActivityNode.d.ts +1 -1
  42. package/dist/fgca/nodes/FGCAChangeNode.d.ts +1 -1
  43. package/dist/fgca/nodes/FGCAFactorNode.d.ts +1 -1
  44. package/dist/fgca/nodes/FGCAGoalNode.d.ts +1 -1
  45. package/dist/fgca/parse-canonical.d.ts +2 -2
  46. package/dist/fgca/parse-canonical.js +2 -2
  47. package/dist/fgca/preview-layout.d.ts +1 -1
  48. package/dist/goals/GoalNode.d.ts +1 -1
  49. package/dist/goals/layout.d.ts +1 -1
  50. package/dist/goals/layout.js +1 -1
  51. package/dist/goals/parse-canonical.d.ts +1 -1
  52. package/dist/goals/parse-canonical.js +1 -1
  53. package/dist/goals/types.d.ts +1 -1
  54. package/dist/goals/validate.js +2 -2
  55. package/dist/link-suspicion.d.ts +43 -0
  56. package/dist/link-suspicion.js +156 -0
  57. package/dist/metric/index.d.ts +4 -0
  58. package/dist/metric/index.js +2 -0
  59. package/dist/metric/types.d.ts +24 -0
  60. package/dist/metric/types.js +7 -0
  61. package/dist/metric/validate.d.ts +7 -0
  62. package/dist/metric/validate.js +90 -0
  63. package/dist/need/index.d.ts +3 -0
  64. package/dist/need/index.js +1 -0
  65. package/dist/need/types.d.ts +21 -0
  66. package/dist/need/types.js +3 -0
  67. package/dist/need/validate.d.ts +7 -0
  68. package/dist/need/validate.js +60 -0
  69. package/dist/repo-validate/check-versioned-attributes.d.ts +4 -0
  70. package/dist/repo-validate/check-versioned-attributes.js +105 -0
  71. package/dist/repo-validate/validate-repo.js +3 -0
  72. package/dist/requirement/index.d.ts +2 -2
  73. package/dist/requirement/index.js +1 -1
  74. package/dist/requirement/types.d.ts +18 -0
  75. package/dist/requirement/types.js +2 -0
  76. package/dist/requirement/validate.js +22 -1
  77. package/dist/risk/index.d.ts +4 -0
  78. package/dist/risk/index.js +2 -0
  79. package/dist/risk/types.d.ts +25 -0
  80. package/dist/risk/types.js +3 -0
  81. package/dist/risk/validate.d.ts +7 -0
  82. package/dist/risk/validate.js +108 -0
  83. package/dist/schema-version.d.ts +9 -6
  84. package/dist/schema-version.js +9 -6
  85. package/dist/theme/themes.js +3 -2
  86. package/dist/validation/index.d.ts +4 -0
  87. package/dist/validation/index.js +2 -0
  88. package/dist/validation/types.d.ts +31 -0
  89. package/dist/validation/types.js +21 -0
  90. package/dist/validation/validate.d.ts +7 -0
  91. package/dist/validation/validate.js +106 -0
  92. package/dist/verification/index.d.ts +4 -0
  93. package/dist/verification/index.js +2 -0
  94. package/dist/verification/types.d.ts +31 -0
  95. package/dist/verification/types.js +12 -0
  96. package/dist/verification/validate.d.ts +7 -0
  97. package/dist/verification/validate.js +104 -0
  98. package/dist/versioned-attribute/index.d.ts +4 -0
  99. package/dist/versioned-attribute/index.js +2 -0
  100. package/dist/versioned-attribute/resolve.d.ts +15 -0
  101. package/dist/versioned-attribute/resolve.js +37 -0
  102. package/dist/versioned-attribute/types.d.ts +12 -0
  103. package/dist/versioned-attribute/types.js +6 -0
  104. package/dist/versioned-attribute/validate.d.ts +17 -0
  105. package/dist/versioned-attribute/validate.js +87 -0
  106. package/dist/webview/render-applications.d.ts +15 -1
  107. package/dist/webview/render-applications.js +7 -2
  108. package/dist/webview/render-blocks.js +6 -4
  109. package/dist/webview/render-capability-map.d.ts +16 -1
  110. package/dist/webview/render-capability-map.js +4 -1
  111. package/dist/webview/render-process.d.ts +1 -1
  112. package/dist/webview/render-process.js +5 -5
  113. package/package.json +9 -6
  114. package/src/activity-card/types.ts +1 -1
  115. package/src/agreement.ts +71 -0
  116. package/src/applications/index.ts +3 -0
  117. package/src/applications/resolve-maturity.ts +66 -0
  118. package/src/applications/validate.ts +23 -0
  119. package/src/capability-map/index.ts +7 -0
  120. package/src/capability-map/resolve-maturity.ts +84 -0
  121. package/src/capability-map/validate.ts +1 -2
  122. package/src/compliance/classify.ts +54 -3
  123. package/src/compliance/confidence.ts +1 -1
  124. package/src/compliance/gap-report.ts +91 -4
  125. package/src/compliance/html.ts +19 -7
  126. package/src/compliance/impact.ts +1 -1
  127. package/src/compliance/index.ts +6 -0
  128. package/src/compliance/markdown.ts +18 -4
  129. package/src/compliance/reverse-index.ts +35 -4
  130. package/src/compliance/trace.ts +7 -1
  131. package/src/compliance/types.ts +75 -2
  132. package/src/compliance/views.ts +1 -1
  133. package/src/compliance-matrix/types.ts +2 -2
  134. package/src/confidence/score.ts +1 -1
  135. package/src/constraint/validate.ts +4 -0
  136. package/src/edge-path.ts +1 -1
  137. package/src/factor/validate.ts +2 -2
  138. package/src/fgca/chain-table.ts +1 -1
  139. package/src/fgca/parse-canonical.ts +2 -2
  140. package/src/fgca/preview-layout.ts +1 -1
  141. package/src/goals/layout.ts +1 -1
  142. package/src/goals/parse-canonical.ts +1 -1
  143. package/src/goals/types.ts +1 -1
  144. package/src/goals/validate.ts +2 -2
  145. package/src/link-suspicion.ts +181 -0
  146. package/src/metric/index.ts +4 -0
  147. package/src/metric/types.ts +38 -0
  148. package/src/metric/validate.ts +102 -0
  149. package/src/need/index.ts +3 -0
  150. package/src/need/types.ts +31 -0
  151. package/src/need/validate.ts +71 -0
  152. package/src/repo-validate/check-versioned-attributes.ts +112 -0
  153. package/src/repo-validate/validate-repo.ts +3 -0
  154. package/src/requirement/index.ts +2 -2
  155. package/src/requirement/types.ts +25 -0
  156. package/src/requirement/validate.ts +25 -1
  157. package/src/risk/index.ts +4 -0
  158. package/src/risk/types.ts +35 -0
  159. package/src/risk/validate.ts +121 -0
  160. package/src/schema-version.ts +9 -6
  161. package/src/theme/themes.ts +3 -2
  162. package/src/validation/index.ts +4 -0
  163. package/src/validation/types.ts +57 -0
  164. package/src/validation/validate.ts +113 -0
  165. package/src/verification/index.ts +4 -0
  166. package/src/verification/types.ts +48 -0
  167. package/src/verification/validate.ts +111 -0
  168. package/src/versioned-attribute/index.ts +4 -0
  169. package/src/versioned-attribute/resolve.ts +45 -0
  170. package/src/versioned-attribute/types.ts +19 -0
  171. package/src/versioned-attribute/validate.ts +109 -0
  172. package/src/webview/render-applications.ts +25 -2
  173. package/src/webview/render-blocks.ts +8 -4
  174. package/src/webview/render-capability-map.ts +23 -1
  175. package/src/webview/render-process.ts +5 -5
  176. package/src/webview/styles.css +6 -0
@@ -0,0 +1,45 @@
1
+ // Current-value resolution for a versioned attribute — CONTRACT.md §9.2.
2
+
3
+ import type { AttributeVersionEntry, VersionedAttributeSidecar } from './types.js';
4
+
5
+ /** Pick the entry with the largest `valid_from <= atDate`.
6
+ * Returns `undefined` when no entry has taken effect yet as of `atDate`
7
+ * (the attribute has not yet taken its first value — CONTRACT.md §9.2 rule
8
+ * 4). Returns `null` when the resolved entry is itself a gap marker
9
+ * (`value: null` — attribute currently unset). */
10
+ export function resolveAttributeValue(
11
+ entries: AttributeVersionEntry[] | undefined,
12
+ atDate: string,
13
+ ): unknown {
14
+ if (!entries || entries.length === 0) return undefined;
15
+ let best: AttributeVersionEntry | undefined;
16
+ for (const entry of entries) {
17
+ if (entry.valid_from <= atDate && (!best || entry.valid_from > best.valid_from)) {
18
+ best = entry;
19
+ }
20
+ }
21
+ return best ? best.value : undefined;
22
+ }
23
+
24
+ /** Resolve every attribute in a sidecar at `atDate`. An attribute with no
25
+ * entry yet in effect is omitted from the result (equivalent to
26
+ * `resolveAttributeValue` returning `undefined`) rather than reported as
27
+ * `null`, which is reserved for an explicit gap marker. */
28
+ export function resolveAttributes(
29
+ sidecar: VersionedAttributeSidecar | null | undefined,
30
+ atDate: string,
31
+ ): Record<string, unknown> {
32
+ const out: Record<string, unknown> = {};
33
+ if (!sidecar) return out;
34
+ for (const name of Object.keys(sidecar.attribute_versions)) {
35
+ const value = resolveAttributeValue(sidecar.attribute_versions[name], atDate);
36
+ if (value !== undefined) out[name] = value;
37
+ }
38
+ return out;
39
+ }
40
+
41
+ /** Today, as a quoted-ISO-8601 date string — the default projection date
42
+ * every resolver/renderer falls back to when the caller supplies none. */
43
+ export function todayIso(): string {
44
+ return new Date().toISOString().slice(0, 10);
45
+ }
@@ -0,0 +1,19 @@
1
+ // Versioned-attribute sidecar (CONTRACT.md §9) — shared shape across every
2
+ // notation that declares a `time_varying` field. A sidecar is a co-located
3
+ // `<primitive_id>.history.yaml` document: no `id`, no admission record, no
4
+ // lifecycle of its own — its temporal window is governed by the target
5
+ // primitive's own `valid_from`/`valid_to` (CONTRACT.md §9.1).
6
+
7
+ /** One version entry in an attribute's history. `value: null` is a gap
8
+ * marker — the attribute is unset from `valid_from` until the next entry. */
9
+ export interface AttributeVersionEntry {
10
+ valid_from: string;
11
+ value: unknown;
12
+ }
13
+
14
+ /** A parsed sidecar document, keyed by attribute name. */
15
+ export interface VersionedAttributeSidecar {
16
+ /** Canonical id of the primitive this sidecar versions. */
17
+ target: string;
18
+ attribute_versions: Record<string, AttributeVersionEntry[]>;
19
+ }
@@ -0,0 +1,109 @@
1
+ // Versioned-attribute sidecar validation — CONTRACT.md §9.3, `VERSIONED-00x`.
2
+ //
3
+ // Split by what each check needs to know:
4
+ // - `parseSidecar` + `validateAttributeArray` here cover VERSIONED-002/003/005,
5
+ // which only need the sidecar document itself (plus, for 005, the target
6
+ // primitive's own lifecycle window).
7
+ // - `VERSIONED-001` (target resolves to an admitted primitive) and
8
+ // `VERSIONED-004` (a time_varying field present inline on the primitive)
9
+ // both need cross-document knowledge — which ids exist, which notation a
10
+ // primitive is — that a single sidecar document doesn't carry. Those are
11
+ // repo-scope concerns; see `repo-validate/check-versioned-attributes.ts`.
12
+
13
+ import type { AttributeVersionEntry, VersionedAttributeSidecar } from './types.js';
14
+
15
+ export interface AttributeArrayFinding {
16
+ code: 'VERSIONED-002' | 'VERSIONED-003' | 'VERSIONED-005';
17
+ severity: 'error' | 'warning';
18
+ message: string;
19
+ }
20
+
21
+ function isAttributeVersionEntry(v: unknown): v is AttributeVersionEntry {
22
+ return typeof v === 'object' && v !== null && !Array.isArray(v) && typeof (v as Record<string, unknown>)['valid_from'] === 'string';
23
+ }
24
+
25
+ /** Parse a raw parsed-YAML mapping into a typed sidecar, or `null` if it
26
+ * isn't shaped like one (missing `target` string or `attribute_versions`
27
+ * map) — not every doc under `canon/elements/**` is a sidecar. */
28
+ export function parseSidecar(data: Record<string, unknown> | null | undefined): VersionedAttributeSidecar | null {
29
+ if (!data) return null;
30
+ const target = data['target'];
31
+ const attributeVersions = data['attribute_versions'];
32
+ if (typeof target !== 'string' || target.trim() === '') return null;
33
+ if (typeof attributeVersions !== 'object' || attributeVersions === null || Array.isArray(attributeVersions)) return null;
34
+
35
+ const out: Record<string, AttributeVersionEntry[]> = {};
36
+ for (const [name, value] of Object.entries(attributeVersions as Record<string, unknown>)) {
37
+ if (!Array.isArray(value)) continue;
38
+ out[name] = value.filter(isAttributeVersionEntry);
39
+ }
40
+ return { target, attribute_versions: out };
41
+ }
42
+
43
+ /** VERSIONED-002/003/005 for one attribute's version array.
44
+ * `targetValidFrom`/`targetValidTo` bound VERSIONED-005 — pass `undefined`
45
+ * for either to skip that half of the check (e.g. the target element could
46
+ * not be found, which is already reported separately as VERSIONED-001). */
47
+ export function validateAttributeArray(
48
+ attributeName: string,
49
+ entries: AttributeVersionEntry[],
50
+ targetValidFrom?: string,
51
+ targetValidTo?: string | null,
52
+ ): AttributeArrayFinding[] {
53
+ const findings: AttributeArrayFinding[] = [];
54
+ const seen = new Set<string>();
55
+ let sorted = true;
56
+ let prev: string | undefined;
57
+
58
+ for (const entry of entries) {
59
+ if (seen.has(entry.valid_from)) {
60
+ findings.push({
61
+ code: 'VERSIONED-002',
62
+ severity: 'error',
63
+ message: `attribute '${attributeName}': duplicate valid_from '${entry.valid_from}'.`,
64
+ });
65
+ }
66
+ seen.add(entry.valid_from);
67
+
68
+ if (prev !== undefined && entry.valid_from < prev) sorted = false;
69
+ prev = entry.valid_from;
70
+
71
+ if (targetValidFrom !== undefined && entry.valid_from < targetValidFrom) {
72
+ findings.push({
73
+ code: 'VERSIONED-005',
74
+ severity: 'error',
75
+ message: `attribute '${attributeName}': entry valid_from '${entry.valid_from}' is before the target's valid_from '${targetValidFrom}'.`,
76
+ });
77
+ }
78
+ if (targetValidTo !== undefined && targetValidTo !== null && entry.valid_from > targetValidTo) {
79
+ findings.push({
80
+ code: 'VERSIONED-005',
81
+ severity: 'error',
82
+ message: `attribute '${attributeName}': entry valid_from '${entry.valid_from}' is after the target's valid_to '${targetValidTo}'.`,
83
+ });
84
+ }
85
+ }
86
+
87
+ if (!sorted) {
88
+ findings.push({
89
+ code: 'VERSIONED-003',
90
+ severity: 'warning',
91
+ message: `attribute '${attributeName}': entries are not sorted by valid_from ascending.`,
92
+ });
93
+ }
94
+
95
+ return findings;
96
+ }
97
+
98
+ /** Run VERSIONED-002/003/005 over every attribute in a parsed sidecar. */
99
+ export function validateSidecar(
100
+ sidecar: VersionedAttributeSidecar,
101
+ targetValidFrom?: string,
102
+ targetValidTo?: string | null,
103
+ ): AttributeArrayFinding[] {
104
+ const findings: AttributeArrayFinding[] = [];
105
+ for (const [name, entries] of Object.entries(sidecar.attribute_versions)) {
106
+ findings.push(...validateAttributeArray(name, entries, targetValidFrom, targetValidTo));
107
+ }
108
+ return findings;
109
+ }
@@ -12,6 +12,8 @@ import type {
12
12
  ApplicationIntegration,
13
13
  ApplicationsCatalogueHeader,
14
14
  } from '../applications/types.js';
15
+ import type { ResolvedApplicationAttributes } from '../applications/resolve-maturity.js';
16
+ import { withResolvedAttributes } from '../applications/resolve-maturity.js';
15
17
  import { escHtml } from './render-util.js';
16
18
 
17
19
  const TYPE_LABEL: Record<string, string> = {
@@ -86,8 +88,28 @@ function renderRow(a: Application): string {
86
88
  </tr>`;
87
89
  }
88
90
 
89
- export function renderApplicationsHtml(catalogue: ApplicationsCatalogueHeader): string {
90
- const rows = catalogue.applications.map(renderRow).join('\n');
91
+ /**
92
+ * Resolved values for owner_role/vendor/maturity — sidecar-bound
93
+ * (CONTRACT.md §9.4) and never inline on an admitted catalogue entry
94
+ * (VERSIONED-004). The host resolves these upstream (see
95
+ * `applications/resolve-maturity.ts`) and passes the result in; this
96
+ * function stays a pure renderer of whatever it's given — no I/O, no
97
+ * write-back. `asOf` is the date the resolution ran at, shown so the view
98
+ * never states an undated value.
99
+ */
100
+ export interface ApplicationsMaturityResolution {
101
+ asOf: string;
102
+ byAppId: Map<string, ResolvedApplicationAttributes>;
103
+ }
104
+
105
+ export function renderApplicationsHtml(
106
+ catalogue: ApplicationsCatalogueHeader,
107
+ resolution?: ApplicationsMaturityResolution,
108
+ ): string {
109
+ const applications = resolution
110
+ ? catalogue.applications.map((a) => withResolvedAttributes(a, resolution.byAppId))
111
+ : catalogue.applications;
112
+ const rows = applications.map(renderRow).join('\n');
91
113
  const emptyRow = catalogue.applications.length === 0
92
114
  ? `<tr><td colspan="7" class="empty-catalogue">No applications defined.</td></tr>`
93
115
  : '';
@@ -99,6 +121,7 @@ export function renderApplicationsHtml(catalogue: ApplicationsCatalogueHeader):
99
121
  ${catalogue.version ? `<span class="catalogue-version">v${escHtml(catalogue.version)}</span>` : ''}
100
122
  </div>
101
123
  ${catalogue.description ? `<div class="catalogue-subtitle">${escHtml(catalogue.description)}</div>` : ''}
124
+ ${resolution ? `<div class="catalogue-resolved-note">Owner Role, Vendor, Maturity resolved as of ${escHtml(resolution.asOf)}</div>` : ''}
102
125
  </header>`;
103
126
  return `<section class="tx-catalogue tx-applications">
104
127
  ${header}
@@ -163,8 +163,6 @@ export function renderBlocksSvg(doc: BlocksFile, options: RenderBlocksOptions =
163
163
  */
164
164
  const GRID_CELL_PAD_X = 8;
165
165
  const GRID_LINE_HEIGHT = 15;
166
- const GRID_EMBED_CSS = `
167
- .blocks-grid-border { fill: none; stroke: var(--ts-border, #cbd5e1); }`;
168
166
 
169
167
  function centeredGridCellTextSvg(
170
168
  lines: string[],
@@ -246,7 +244,13 @@ export function renderGridBody(layout: GridLayout, ox: number, oy: number): stri
246
244
  parts.push(`<line class="diagram-edge" x1="${colLineX}" y1="${gridY1}" x2="${colLineX}" y2="${gridY2}"/>`);
247
245
  }
248
246
 
249
- parts.push(`<rect class="blocks-grid-border" x="${ox}" y="${oy}" width="${tw}" height="${th}"/>`);
247
+ // Explicit fill="none" alongside the class: this rect covers the full grid
248
+ // bounds and is the last (topmost) element emitted, so if `.blocks-grid-border`
249
+ // is ever missing from a host's CSS (as it was in the VS Code webview path —
250
+ // see the grid-preview regression), it must not fall back to SVG's default opaque black fill.
251
+ parts.push(
252
+ `<rect class="blocks-grid-border" fill="none" x="${ox}" y="${oy}" width="${tw}" height="${th}"/>`,
253
+ );
250
254
 
251
255
  return parts.join('\n');
252
256
  }
@@ -270,7 +274,7 @@ export function renderGridLayoutSvg(layout: GridLayout, options: RenderGridLayou
270
274
  const oy = PAD + topInset;
271
275
 
272
276
  const body = renderGridBody(layout, ox, oy);
273
- const styleLine = embedCssTheme ? `\n<style>${generateSvgEmbedCss(embedCssTheme)}${GRID_EMBED_CSS}</style>` : '';
277
+ const styleLine = embedCssTheme ? `\n<style>${generateSvgEmbedCss(embedCssTheme)}</style>` : '';
274
278
 
275
279
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">${styleLine}
276
280
  ${title}
@@ -4,6 +4,8 @@
4
4
  * HTML fragment for the JCEF host (Step 4 of ADR 0001).
5
5
  */
6
6
  import type { CapabilityMapHeader, CapabilityNode } from '../capability-map/types.js';
7
+ import type { ResolvedCapabilityAttributes } from '../capability-map/resolve-maturity.js';
8
+ import { withResolvedCapabilityMap } from '../capability-map/resolve-maturity.js';
7
9
  import { escHtml } from './render-util.js';
8
10
 
9
11
  const MATURITY_LABEL: Record<number, string> = {
@@ -62,7 +64,26 @@ function renderCapabilityCard(node: CapabilityNode, depth: number): string {
62
64
  </div>`;
63
65
  }
64
66
 
65
- export function renderCapabilityMapHtml(map: CapabilityMapHeader): string {
67
+ /**
68
+ * Resolved values for current_maturity/target_maturity/owner_role/
69
+ * target_date — sidecar-bound (CONTRACT.md §9.4) on the standalone
70
+ * CAPABILITY-* primitive a nested entry references (the 2026-08-05
71
+ * packages decision). The host resolves
72
+ * these upstream (see `capability-map/resolve-maturity.ts`) and passes the
73
+ * result in; this function stays a pure renderer of whatever it's given —
74
+ * no I/O, no write-back. `asOf` is the date the resolution ran at, shown so
75
+ * the view never states an undated value.
76
+ */
77
+ export interface CapabilityMapMaturityResolution {
78
+ asOf: string;
79
+ byId: Map<string, ResolvedCapabilityAttributes>;
80
+ }
81
+
82
+ export function renderCapabilityMapHtml(
83
+ rawMap: CapabilityMapHeader,
84
+ resolution?: CapabilityMapMaturityResolution,
85
+ ): string {
86
+ const map = resolution ? withResolvedCapabilityMap(rawMap, resolution.byId) : rawMap;
66
87
  const header = `<header class="catalogue-header">
67
88
  <div class="catalogue-title">${escHtml(map.name)}</div>
68
89
  <div class="catalogue-meta">
@@ -70,6 +91,7 @@ export function renderCapabilityMapHtml(map: CapabilityMapHeader): string {
70
91
  <span class="catalogue-updated">Assessed ${escHtml(map.assessment_date)}</span>
71
92
  </div>
72
93
  ${map.description ? `<div class="catalogue-subtitle">${escHtml(map.description)}</div>` : ''}
94
+ ${resolution ? `<div class="catalogue-resolved-note">Current Maturity, Target Maturity, Owner Role, Target Date resolved as of ${escHtml(resolution.asOf)}</div>` : ''}
73
95
  </header>`;
74
96
  if (map.capabilities.length === 0) {
75
97
  return `<section class="tx-catalogue tx-capability-map">
@@ -116,17 +116,17 @@ export const BPMN_PROCESS_CSS = `
116
116
  .bpmn-pool-name { fill: var(--ts-bg-elevated,#f1f5f9); stroke: var(--ts-node-stroke,#004d67); stroke-width: 0.75; }
117
117
  .bpmn-lane { fill: var(--ts-bg,#ffffff); stroke: var(--ts-node-stroke,#004d67); stroke-width: 0.75; }
118
118
  .bpmn-lane-header { fill: var(--ts-bg-elevated,#f1f5f9); stroke: var(--ts-node-stroke,#004d67); stroke-width: 0.75; }
119
- .bpmn-pool-label { fill: var(--ts-text-primary,#0d2b35); font-size: 11px; font-weight: 700; }
120
- .bpmn-lane-label { fill: var(--ts-text-primary,#0d2b35); font-size: 11px; font-weight: 600; }
119
+ .bpmn-pool-label { fill: var(--ts-text-primary,#0d2b35); font-family: var(--vscode-font-family, system-ui, -apple-system, sans-serif); font-size: 11px; font-weight: 700; }
120
+ .bpmn-lane-label { fill: var(--ts-text-primary,#0d2b35); font-family: var(--vscode-font-family, system-ui, -apple-system, sans-serif); font-size: 11px; font-weight: 600; }
121
121
  .bpmn-task { fill: var(--ts-bg,#ffffff); stroke: var(--ts-node-stroke,#004d67); stroke-width: 1.5; }
122
- .bpmn-task-name { fill: var(--ts-text-primary,#0d2b35); font-size: 11px; text-anchor: middle; }
122
+ .bpmn-task-name { fill: var(--ts-text-primary,#0d2b35); font-family: var(--vscode-font-family, system-ui, -apple-system, sans-serif); font-size: 11px; text-anchor: middle; }
123
123
  .bpmn-event { fill: var(--ts-bg,#ffffff); stroke: var(--ts-node-stroke,#004d67); }
124
124
  .bpmn-event-start { stroke-width: 1.5; }
125
125
  .bpmn-event-end { stroke-width: 4; }
126
- .bpmn-event-label { fill: var(--ts-text-secondary,#516970); font-size: 10px; text-anchor: middle; }
126
+ .bpmn-event-label { fill: var(--ts-text-secondary,#516970); font-family: var(--vscode-font-family, system-ui, -apple-system, sans-serif); font-size: 10px; text-anchor: middle; }
127
127
  .bpmn-gateway { fill: var(--ts-bg,#ffffff); stroke: var(--ts-node-stroke,#004d67); stroke-width: 1.5; }
128
128
  .bpmn-gateway-marker { stroke: var(--ts-node-stroke,#004d67); stroke-width: 2.5; stroke-linecap: round; fill: none; }
129
- .bpmn-gateway-label { fill: var(--ts-text-secondary,#516970); font-size: 10px; text-anchor: middle; }
129
+ .bpmn-gateway-label { fill: var(--ts-text-secondary,#516970); font-family: var(--vscode-font-family, system-ui, -apple-system, sans-serif); font-size: 10px; text-anchor: middle; }
130
130
  .bpmn-seq-flow { fill: none; stroke: var(--ts-edge-stroke,#004d67); stroke-width: 1.5; }
131
131
  .bpmn-default-mark { stroke: var(--ts-edge-stroke,#004d67); stroke-width: 1.5; stroke-linecap: round; }
132
132
  .bpmn-assoc { fill: none; stroke: var(--ts-edge-stroke,#004d67); stroke-width: 1; stroke-dasharray: 4 2; }
@@ -140,6 +140,12 @@ body {
140
140
  color: var(--tx-fg);
141
141
  }
142
142
 
143
+ .catalogue-resolved-note {
144
+ margin-top: 6px;
145
+ color: var(--tx-muted);
146
+ font-size: 11px;
147
+ }
148
+
143
149
  .catalogue-table {
144
150
  width: 100%;
145
151
  border-collapse: collapse;