@transitrix/diagrams 1.8.21 → 1.10.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 (190) 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/codex/index.d.ts +1 -1
  17. package/dist/codex/index.js +1 -1
  18. package/dist/codex/types.d.ts +9 -2
  19. package/dist/codex/types.js +10 -3
  20. package/dist/codex/validate.js +29 -3
  21. package/dist/compliance/classify.d.ts +21 -2
  22. package/dist/compliance/classify.js +68 -13
  23. package/dist/compliance/confidence.js +1 -1
  24. package/dist/compliance/gap-report.d.ts +31 -1
  25. package/dist/compliance/gap-report.js +55 -3
  26. package/dist/compliance/html.js +14 -6
  27. package/dist/compliance/impact.js +1 -1
  28. package/dist/compliance/index.d.ts +3 -1
  29. package/dist/compliance/index.js +2 -0
  30. package/dist/compliance/markdown.js +26 -4
  31. package/dist/compliance/reverse-index.d.ts +6 -1
  32. package/dist/compliance/reverse-index.js +27 -3
  33. package/dist/compliance/trace.js +5 -1
  34. package/dist/compliance/types.d.ts +70 -0
  35. package/dist/compliance/types.js +1 -2
  36. package/dist/compliance/views.js +1 -1
  37. package/dist/compliance-matrix/build.js +0 -0
  38. package/dist/compliance-matrix/types.d.ts +1 -1
  39. package/dist/compliance-matrix/types.js +1 -1
  40. package/dist/confidence/score.js +1 -1
  41. package/dist/constraint/validate.js +3 -0
  42. package/dist/edge-path.js +1 -1
  43. package/dist/factor/validate.js +2 -2
  44. package/dist/fgca/chain-table.js +1 -1
  45. package/dist/fgca/nodeTypes.d.ts +4 -4
  46. package/dist/fgca/nodes/FGCAActivityNode.d.ts +1 -1
  47. package/dist/fgca/nodes/FGCAChangeNode.d.ts +1 -1
  48. package/dist/fgca/nodes/FGCAFactorNode.d.ts +1 -1
  49. package/dist/fgca/nodes/FGCAGoalNode.d.ts +1 -1
  50. package/dist/fgca/parse-canonical.d.ts +2 -2
  51. package/dist/fgca/parse-canonical.js +2 -2
  52. package/dist/fgca/preview-layout.d.ts +1 -1
  53. package/dist/goals/GoalNode.d.ts +1 -1
  54. package/dist/goals/layout.d.ts +1 -1
  55. package/dist/goals/layout.js +1 -1
  56. package/dist/goals/parse-canonical.d.ts +1 -1
  57. package/dist/goals/parse-canonical.js +1 -1
  58. package/dist/goals/types.d.ts +1 -1
  59. package/dist/goals/validate.js +2 -2
  60. package/dist/link-suspicion.d.ts +43 -0
  61. package/dist/link-suspicion.js +156 -0
  62. package/dist/metric/index.d.ts +4 -0
  63. package/dist/metric/index.js +2 -0
  64. package/dist/metric/types.d.ts +24 -0
  65. package/dist/metric/types.js +7 -0
  66. package/dist/metric/validate.d.ts +7 -0
  67. package/dist/metric/validate.js +90 -0
  68. package/dist/need/index.d.ts +3 -0
  69. package/dist/need/index.js +1 -0
  70. package/dist/need/types.d.ts +21 -0
  71. package/dist/need/types.js +3 -0
  72. package/dist/need/validate.d.ts +7 -0
  73. package/dist/need/validate.js +60 -0
  74. package/dist/repo-validate/check-candidate-fields.d.ts +6 -0
  75. package/dist/repo-validate/check-candidate-fields.js +87 -0
  76. package/dist/repo-validate/check-versioned-attributes.d.ts +4 -0
  77. package/dist/repo-validate/check-versioned-attributes.js +105 -0
  78. package/dist/repo-validate/validate-repo.js +7 -0
  79. package/dist/requirement/index.d.ts +2 -2
  80. package/dist/requirement/index.js +1 -1
  81. package/dist/requirement/types.d.ts +19 -1
  82. package/dist/requirement/types.js +3 -1
  83. package/dist/requirement/validate.js +22 -1
  84. package/dist/risk/index.d.ts +4 -0
  85. package/dist/risk/index.js +2 -0
  86. package/dist/risk/types.d.ts +25 -0
  87. package/dist/risk/types.js +3 -0
  88. package/dist/risk/validate.d.ts +7 -0
  89. package/dist/risk/validate.js +108 -0
  90. package/dist/schema-version.d.ts +9 -6
  91. package/dist/schema-version.js +9 -6
  92. package/dist/theme/themes.js +3 -2
  93. package/dist/validation/index.d.ts +4 -0
  94. package/dist/validation/index.js +2 -0
  95. package/dist/validation/types.d.ts +31 -0
  96. package/dist/validation/types.js +21 -0
  97. package/dist/validation/validate.d.ts +7 -0
  98. package/dist/validation/validate.js +106 -0
  99. package/dist/verification/index.d.ts +4 -0
  100. package/dist/verification/index.js +2 -0
  101. package/dist/verification/types.d.ts +31 -0
  102. package/dist/verification/types.js +12 -0
  103. package/dist/verification/validate.d.ts +7 -0
  104. package/dist/verification/validate.js +104 -0
  105. package/dist/versioned-attribute/index.d.ts +4 -0
  106. package/dist/versioned-attribute/index.js +2 -0
  107. package/dist/versioned-attribute/resolve.d.ts +15 -0
  108. package/dist/versioned-attribute/resolve.js +37 -0
  109. package/dist/versioned-attribute/types.d.ts +12 -0
  110. package/dist/versioned-attribute/types.js +6 -0
  111. package/dist/versioned-attribute/validate.d.ts +17 -0
  112. package/dist/versioned-attribute/validate.js +87 -0
  113. package/dist/webview/entry.js +11 -4
  114. package/dist/webview/render-applications.d.ts +15 -1
  115. package/dist/webview/render-applications.js +7 -2
  116. package/dist/webview/render-blocks.js +6 -4
  117. package/dist/webview/render-capability-map.d.ts +16 -1
  118. package/dist/webview/render-capability-map.js +4 -1
  119. package/dist/webview/render-process.d.ts +1 -1
  120. package/dist/webview/render-process.js +5 -5
  121. package/package.json +9 -6
  122. package/src/activity-card/types.ts +1 -1
  123. package/src/agreement.ts +71 -0
  124. package/src/applications/index.ts +3 -0
  125. package/src/applications/resolve-maturity.ts +66 -0
  126. package/src/applications/validate.ts +23 -0
  127. package/src/capability-map/index.ts +7 -0
  128. package/src/capability-map/resolve-maturity.ts +84 -0
  129. package/src/capability-map/validate.ts +1 -2
  130. package/src/codex/index.ts +1 -1
  131. package/src/codex/types.ts +11 -3
  132. package/src/codex/validate.ts +30 -2
  133. package/src/compliance/classify.ts +87 -14
  134. package/src/compliance/confidence.ts +1 -1
  135. package/src/compliance/gap-report.ts +91 -4
  136. package/src/compliance/html.ts +18 -6
  137. package/src/compliance/impact.ts +1 -1
  138. package/src/compliance/index.ts +6 -0
  139. package/src/compliance/markdown.ts +18 -4
  140. package/src/compliance/reverse-index.ts +35 -4
  141. package/src/compliance/trace.ts +7 -1
  142. package/src/compliance/types.ts +75 -2
  143. package/src/compliance/views.ts +1 -1
  144. package/src/compliance-matrix/build.ts +0 -0
  145. package/src/compliance-matrix/types.ts +2 -2
  146. package/src/confidence/score.ts +1 -1
  147. package/src/constraint/validate.ts +4 -0
  148. package/src/edge-path.ts +1 -1
  149. package/src/factor/validate.ts +2 -2
  150. package/src/fgca/chain-table.ts +1 -1
  151. package/src/fgca/parse-canonical.ts +2 -2
  152. package/src/fgca/preview-layout.ts +1 -1
  153. package/src/goals/layout.ts +1 -1
  154. package/src/goals/parse-canonical.ts +1 -1
  155. package/src/goals/types.ts +1 -1
  156. package/src/goals/validate.ts +2 -2
  157. package/src/link-suspicion.ts +181 -0
  158. package/src/metric/index.ts +4 -0
  159. package/src/metric/types.ts +38 -0
  160. package/src/metric/validate.ts +102 -0
  161. package/src/need/index.ts +3 -0
  162. package/src/need/types.ts +31 -0
  163. package/src/need/validate.ts +71 -0
  164. package/src/repo-validate/check-candidate-fields.ts +93 -0
  165. package/src/repo-validate/check-versioned-attributes.ts +112 -0
  166. package/src/repo-validate/validate-repo.ts +7 -0
  167. package/src/requirement/index.ts +2 -2
  168. package/src/requirement/types.ts +26 -1
  169. package/src/requirement/validate.ts +25 -1
  170. package/src/risk/index.ts +4 -0
  171. package/src/risk/types.ts +35 -0
  172. package/src/risk/validate.ts +121 -0
  173. package/src/schema-version.ts +9 -6
  174. package/src/theme/themes.ts +3 -2
  175. package/src/validation/index.ts +4 -0
  176. package/src/validation/types.ts +57 -0
  177. package/src/validation/validate.ts +113 -0
  178. package/src/verification/index.ts +4 -0
  179. package/src/verification/types.ts +48 -0
  180. package/src/verification/validate.ts +111 -0
  181. package/src/versioned-attribute/index.ts +4 -0
  182. package/src/versioned-attribute/resolve.ts +45 -0
  183. package/src/versioned-attribute/types.ts +19 -0
  184. package/src/versioned-attribute/validate.ts +109 -0
  185. package/src/webview/entry.ts +13 -6
  186. package/src/webview/render-applications.ts +25 -2
  187. package/src/webview/render-blocks.ts +8 -4
  188. package/src/webview/render-capability-map.ts +23 -1
  189. package/src/webview/render-process.ts +5 -5
  190. package/src/webview/styles.css +6 -0
@@ -0,0 +1,105 @@
1
+ // Versioned-attribute sidecar checks (CONTRACT.md §9) — `VERSIONED-001..005`.
2
+ //
3
+ // A sidecar is any doc under `canon/elements/**` shaped like one (`target` +
4
+ // `attribute_versions`, no `id` — same "no id -> not an element" convention
5
+ // `docId` already uses to skip these docs everywhere else in this file's
6
+ // sibling checks). Both halves of §9.3 live here:
7
+ // - VERSIONED-001 — a sidecar's `target` must resolve to an admitted
8
+ // primitive in this same model.
9
+ // - VERSIONED-002/003/005 — the sidecar's own array shape, delegated to
10
+ // the shared `../versioned-attribute` module (needs VERSIONED-005's
11
+ // bound: the target's own `valid_from`/`valid_to`, read from the
12
+ // resolved target doc).
13
+ // - VERSIONED-004 — a field declared `time_varying` present inline on its
14
+ // primitive, instead of only in the sidecar.
15
+ //
16
+ // `TIME_VARYING_FIELDS` is deliberately narrower than the full candidate
17
+ // list in CONTRACT.md §9.4: it only enforces fields already `time_varying`
18
+ // on methodology's *currently-merged* notation specs. `capability` covers
19
+ // `current_maturity`, `target_maturity`, `owner_role`, `target_date` per
20
+ // `05-capability-map.md` §13/§14. Applications-catalogue `maturity` (and its
21
+ // sibling `owner_role`/`vendor`) is on the same 2026-08-02 maturity ADR but
22
+ // is not enforced here yet — it lives on the `applications[]` list inside a
23
+ // catalogue view document, not on a standalone element primitive, and this
24
+ // check only walks `elements`.
25
+ import { parseSidecar, validateSidecar } from '../versioned-attribute/index.js';
26
+ import { docId } from './validate-repo.js';
27
+ const PScope = 'repo';
28
+ const TIME_VARYING_FIELDS = {
29
+ capability: ['current_maturity', 'target_maturity', 'owner_role', 'target_date'],
30
+ };
31
+ function readString(data, key) {
32
+ const v = data[key];
33
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
34
+ }
35
+ /** VERSIONED-004 — a time_varying field present inline on its primitive. */
36
+ function checkInlineTimeVarying(elements, findings) {
37
+ for (const doc of elements) {
38
+ if (!doc.data)
39
+ continue;
40
+ const id = docId(doc);
41
+ if (!id)
42
+ continue; // sidecars carry no id — not a primitive
43
+ const notation = doc.data['notation'];
44
+ if (typeof notation !== 'string')
45
+ continue;
46
+ const fields = TIME_VARYING_FIELDS[notation];
47
+ if (!fields)
48
+ continue;
49
+ for (const field of fields) {
50
+ if (doc.data[field] !== undefined) {
51
+ findings.push({
52
+ scope: PScope,
53
+ id,
54
+ ruleId: 'VERSIONED-004',
55
+ message: `VERSIONED-004: '${id}' declares '${field}' inline; it is time_varying and belongs in ` +
56
+ `the sidecar '${id}.history.yaml' (CONTRACT.md §9), not on the primitive.`,
57
+ });
58
+ }
59
+ }
60
+ }
61
+ }
62
+ /** VERSIONED-001/002/003/005 — every sidecar doc found under `canon/elements/**`. */
63
+ function checkSidecars(elements, findings) {
64
+ const elementById = new Map();
65
+ for (const doc of elements) {
66
+ const id = docId(doc);
67
+ if (id)
68
+ elementById.set(id, doc);
69
+ }
70
+ for (const doc of elements) {
71
+ if (!doc.data || docId(doc))
72
+ continue; // sidecars have no id
73
+ const sidecar = parseSidecar(doc.data);
74
+ if (!sidecar)
75
+ continue; // not shaped like a sidecar — ignore, same as docId's element/non-element split
76
+ const targetDoc = elementById.get(sidecar.target);
77
+ if (!targetDoc) {
78
+ findings.push({
79
+ scope: PScope,
80
+ id: sidecar.target,
81
+ ruleId: 'VERSIONED-001',
82
+ message: `VERSIONED-001: sidecar '${doc.path}' target '${sidecar.target}' does not resolve to an admitted primitive.`,
83
+ });
84
+ continue;
85
+ }
86
+ const targetValidFrom = targetDoc.data ? readString(targetDoc.data, 'valid_from') : undefined;
87
+ const validToRaw = targetDoc.data?.['valid_to'];
88
+ const targetValidTo = validToRaw === null ? null : typeof validToRaw === 'string' ? validToRaw : undefined;
89
+ for (const f of validateSidecar(sidecar, targetValidFrom, targetValidTo)) {
90
+ findings.push({
91
+ scope: PScope,
92
+ id: sidecar.target,
93
+ ruleId: f.code,
94
+ severity: f.severity,
95
+ message: `${f.code}: sidecar '${doc.path}' ${f.message}`,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ /** Run the versioned-attribute sidecar checks (VERSIONED-001..005) over the
101
+ * loaded element set and append findings. Pure, deterministic order. */
102
+ export function checkVersionedAttributes(input, findings) {
103
+ checkInlineTimeVarying(input.elements, findings);
104
+ checkSidecars(input.elements, findings);
105
+ }
@@ -28,6 +28,8 @@
28
28
  // deferred per the ADR.
29
29
  import { checkStrategyChainSemantics } from './check-strategy-chain.js';
30
30
  import { checkElementHygiene } from './check-element-hygiene.js';
31
+ import { checkVersionedAttributes } from './check-versioned-attributes.js';
32
+ import { checkCandidateFields } from './check-candidate-fields.js';
31
33
  const PScope = 'repo';
32
34
  /** Statuses that, per lint.py's policy check, require an owner. */
33
35
  const OWNER_REQUIRED_STATUSES = new Set(['Active', 'Production']);
@@ -412,5 +414,10 @@ export function validateRepoModel(input) {
412
414
  // Phase 8 — standalone-element envelope rules ported from DSM's Go
413
415
  // Validate*Element functions (GOAL-ELEM-001..003, ACTION-001/002/005).
414
416
  checkElementHygiene(input, findings);
417
+ // Phase 9 — versioned-attribute sidecar rules (CONTRACT.md §9, VERSIONED-001..005).
418
+ checkVersionedAttributes(input, findings);
419
+ // Phase 10 — candidate-only fields on admitted canon (ELEMENT_PRIMITIVES.md
420
+ // §7.29, ADMIT-009).
421
+ checkCandidateFields(input, findings);
415
422
  return findings;
416
423
  }
@@ -1,4 +1,4 @@
1
- export type { Requirement, RequirementSeverity, GateChecks } from './types.js';
2
- export { REQUIREMENT_DERIVED_FROM_TYPES } from './types.js';
1
+ export type { Requirement, RequirementSeverity, RequirementLevel, RequirementKind, GateChecks } from './types.js';
2
+ export { REQUIREMENT_DERIVED_FROM_TYPES, REQUIREMENT_LEVELS, REQUIREMENT_KINDS } from './types.js';
3
3
  export { validateRequirement } from './validate.js';
4
4
  export type { RequirementValidateOptions } from './validate.js';
@@ -1,2 +1,2 @@
1
- export { REQUIREMENT_DERIVED_FROM_TYPES } from './types.js';
1
+ export { REQUIREMENT_DERIVED_FROM_TYPES, REQUIREMENT_LEVELS, REQUIREMENT_KINDS } from './types.js';
2
2
  export { validateRequirement } from './validate.js';
@@ -1,3 +1,4 @@
1
+ import type { AgreementValue } from '../agreement.js';
1
2
  export type RequirementSeverity = 'high' | 'medium' | 'low';
2
3
  /** Standard canon admission gate checks (CONTRACT.md §6). */
3
4
  export interface GateChecks {
@@ -6,7 +7,13 @@ export interface GateChecks {
6
7
  completeness?: string;
7
8
  }
8
9
  /** TYPEs a requirement may be derived from (15-requirement.md §2, REQ-003). */
9
- export declare const REQUIREMENT_DERIVED_FROM_TYPES: readonly ["LAW", "REGULATION", "POLICY", "INTERNAL_STANDARD"];
10
+ export declare const REQUIREMENT_DERIVED_FROM_TYPES: readonly ["LAW", "REGULATION", "POLICY", "INTERNAL_STANDARD", "PRINCIPLE"];
11
+ /** ISO/IEC/IEEE 29148 specification-tier ladder (15-requirement.md §2.5, REQ-005). */
12
+ export type RequirementLevel = 'stakeholder' | 'system' | 'software';
13
+ export declare const REQUIREMENT_LEVELS: readonly RequirementLevel[];
14
+ /** Functional vs quality classification (15-requirement.md §2.6, REQ-006). */
15
+ export type RequirementKind = 'functional' | 'quality';
16
+ export declare const REQUIREMENT_KINDS: readonly RequirementKind[];
10
17
  export interface Requirement {
11
18
  notation: 'requirement';
12
19
  id: string;
@@ -14,8 +21,19 @@ export interface Requirement {
14
21
  description: string;
15
22
  /** Organisation-defined priority. */
16
23
  severity?: RequirementSeverity;
24
+ /** ISO/IEC/IEEE 29148 specification tier (§2.5, REQ-005). */
25
+ level?: RequirementLevel;
26
+ /** Functional vs quality classification (§2.6, REQ-006). */
27
+ kind?: RequirementKind;
17
28
  /** Typed IDs of the codex source documents this requirement is drawn from. */
18
29
  derived_from?: string[];
30
+ /** Typed ID of the upstream NEED this requirement traces to (§2.7, REQ-SERVES-001). Optional, singular. */
31
+ serves?: string;
32
+ /** `draft` \| `agreed` \| `disputed`. Absent ⇒ `agreed` (back-compat). */
33
+ agreement?: AgreementValue;
34
+ /** Required whenever `agreement` is present (AGREE-003). Written only by a human when `agreement: agreed` (AGREE-002). */
35
+ agreed_by?: string;
36
+ agreed_at?: string;
19
37
  zone: 'canon';
20
38
  admitted_at: string;
21
39
  admitted_by: string;
@@ -1,4 +1,6 @@
1
1
  // REQUIREMENT — motivation-layer positive obligation.
2
2
  // Schema: methodology notations/elements/15-requirement.md §2.
3
3
  /** TYPEs a requirement may be derived from (15-requirement.md §2, REQ-003). */
4
- export const REQUIREMENT_DERIVED_FROM_TYPES = ['LAW', 'REGULATION', 'POLICY', 'INTERNAL_STANDARD'];
4
+ export const REQUIREMENT_DERIVED_FROM_TYPES = ['LAW', 'REGULATION', 'POLICY', 'INTERNAL_STANDARD', 'PRINCIPLE'];
5
+ export const REQUIREMENT_LEVELS = ['stakeholder', 'system', 'software'];
6
+ export const REQUIREMENT_KINDS = ['functional', 'quality'];
@@ -9,7 +9,8 @@
9
9
  // supplied; the TYPE check (REQ-003) is derivable from the id prefix and runs
10
10
  // either way.
11
11
  import { typeOfId, isCanonicalIdOfType } from '../typed-id.js';
12
- import { REQUIREMENT_DERIVED_FROM_TYPES } from './types.js';
12
+ import { checkAgreement } from '../agreement.js';
13
+ import { REQUIREMENT_DERIVED_FROM_TYPES, REQUIREMENT_LEVELS, REQUIREMENT_KINDS } from './types.js';
13
14
  const REQUIRED_FIELDS = [
14
15
  'notation', 'name', 'description', 'zone', 'admitted_at', 'admitted_by', 'gate_checks', 'valid_from',
15
16
  ];
@@ -77,5 +78,25 @@ export function validateRequirement(input, options = {}) {
77
78
  });
78
79
  }
79
80
  }
81
+ // REQ-005 — level closed vocabulary (optional; only checked when present).
82
+ if (r.level !== undefined && !REQUIREMENT_LEVELS.includes(r.level)) {
83
+ errors.push({ code: 'REQ-005', message: `level "${String(r.level)}" must be one of ${REQUIREMENT_LEVELS.join(', ')}.`, path: 'level' });
84
+ }
85
+ // REQ-006 — kind closed vocabulary (optional; only checked when present).
86
+ if (r.kind !== undefined && !REQUIREMENT_KINDS.includes(r.kind)) {
87
+ errors.push({ code: 'REQ-006', message: `kind "${String(r.kind)}" must be one of ${REQUIREMENT_KINDS.join(', ')}.`, path: 'kind' });
88
+ }
89
+ // REQ-SERVES-001 — serves resolves to an admitted NEED (optional, singular).
90
+ if (r.serves !== undefined) {
91
+ const serves = r.serves;
92
+ if (typeof serves !== 'string' || serves.trim() === '' || typeOfId(serves) !== 'NEED') {
93
+ errors.push({ code: 'REQ-SERVES-001', message: `serves "${String(serves)}" must be a typed NEED id.`, path: 'serves' });
94
+ }
95
+ else if (options.catalog && options.catalog.typeOf(serves) === undefined) {
96
+ errors.push({ code: 'REQ-SERVES-001', message: `serves "${serves}" does not resolve to an admitted NEED.`, path: 'serves' });
97
+ }
98
+ }
99
+ // AGREE-001..003 — agreement axis (CONTRACT.md §6.3.1), optional; absent ⇒ agreed.
100
+ errors.push(...checkAgreement(r));
80
101
  return { valid: errors.length === 0, errors, warnings };
81
102
  }
@@ -0,0 +1,4 @@
1
+ export type { Risk, RiskLevel } from './types.js';
2
+ export { RISK_LEVELS } from './types.js';
3
+ export { validateRisk } from './validate.js';
4
+ export type { RiskValidateOptions } from './validate.js';
@@ -0,0 +1,2 @@
1
+ export { RISK_LEVELS } from './types.js';
2
+ export { validateRisk } from './validate.js';
@@ -0,0 +1,25 @@
1
+ import type { GateChecks } from '../requirement/types.js';
2
+ /** Likelihood / impact / residual severity vocabulary (§7.26). */
3
+ export type RiskLevel = 'low' | 'medium' | 'high';
4
+ export declare const RISK_LEVELS: readonly RiskLevel[];
5
+ export interface Risk {
6
+ notation: 'risk';
7
+ id: string;
8
+ name: string;
9
+ likelihood: RiskLevel;
10
+ impact: RiskLevel;
11
+ residual: RiskLevel;
12
+ /** ROLE-… accountable for tracking and treating this risk. */
13
+ owner_role: string;
14
+ /** Typed IDs of the elements this risk threatens. Non-empty; any TYPE. */
15
+ threatens: string[];
16
+ /** Typed IDs (REQUIREMENT-… / CONSTRAINT-…) of the treatment obligations. */
17
+ treated_by?: string[];
18
+ description?: string;
19
+ zone: 'canon';
20
+ admitted_at: string;
21
+ admitted_by: string;
22
+ gate_checks: GateChecks;
23
+ valid_from: string;
24
+ valid_to: string | null;
25
+ }
@@ -0,0 +1,3 @@
1
+ // RISK — motivation-layer projected event (no ArchiMate counterpart).
2
+ // Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.26.
3
+ export const RISK_LEVELS = ['low', 'medium', 'high'];
@@ -0,0 +1,7 @@
1
+ import type { ValidationResult } from '../validation-types.js';
2
+ import { type CanonCatalog } from '../typed-id.js';
3
+ export interface RiskValidateOptions {
4
+ /** When provided, RISK-003/004 enforce artefact existence for cross-refs. */
5
+ catalog?: CanonCatalog;
6
+ }
7
+ export declare function validateRisk(input: unknown, options?: RiskValidateOptions): ValidationResult;
@@ -0,0 +1,108 @@
1
+ // RISK validator — methodology ELEMENT_PRIMITIVES.md §7.26 / §9.
2
+ //
3
+ // Codes:
4
+ // RISK-001 — shape / id grammar / required envelope + per-type fields
5
+ // (likelihood, impact, residual, owner_role, threatens).
6
+ // RISK-002 — likelihood / impact / residual outside {low, medium, high}.
7
+ // RISK-003 — threatens is empty, or an entry does not resolve to an
8
+ // admitted element in canon (no TYPE restriction — any core
9
+ // element may be threatened).
10
+ // RISK-004 — a treated_by entry does not resolve, or resolves to a TYPE
11
+ // other than REQUIREMENT / CONSTRAINT.
12
+ // RISK-COVERAGE-001 (warning) — treated_by is empty/absent (an untreated
13
+ // risk). Unlike the cross-cutting *-COVERAGE-001 rules this
14
+ // reads only the RISK element's own field — no catalogue scan
15
+ // required — so it is implemented inline here rather than via
16
+ // the compliance reverse-index.
17
+ //
18
+ // Resolution rules (RISK-003/004) that need artefact *existence* run only
19
+ // when a `CanonCatalog` is supplied; the TYPE check RISK-004 also carries is
20
+ // derivable from the id prefix and runs either way.
21
+ import { typeOfId, isCanonicalIdOfType } from '../typed-id.js';
22
+ import { RISK_LEVELS } from './types.js';
23
+ const TREATED_BY_TYPES = ['REQUIREMENT', 'CONSTRAINT'];
24
+ export function validateRisk(input, options = {}) {
25
+ const errors = [];
26
+ const warnings = [];
27
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
28
+ errors.push({ code: 'RISK-001', message: 'Risk must be a YAML mapping.' });
29
+ return { valid: false, errors, warnings };
30
+ }
31
+ const r = input;
32
+ // RISK-001 — id grammar + notation tag + envelope + plain per-type fields.
33
+ if (!isCanonicalIdOfType(r.id, 'RISK')) {
34
+ errors.push({ code: 'RISK-001', message: `id "${String(r.id)}" must match RISK-[<middle>-]<INTEGER>.`, path: 'id' });
35
+ }
36
+ if (r.notation !== 'risk') {
37
+ errors.push({ code: 'RISK-001', message: 'notation must be the fixed value "risk".', path: 'notation' });
38
+ }
39
+ if (r.zone !== 'canon') {
40
+ errors.push({ code: 'RISK-001', message: 'zone is required and must be "canon".', path: 'zone' });
41
+ }
42
+ for (const f of ['name', 'admitted_at', 'admitted_by', 'valid_from', 'owner_role']) {
43
+ if (typeof r[f] !== 'string' || r[f].trim() === '') {
44
+ errors.push({ code: 'RISK-001', message: `${f} is required.`, path: f });
45
+ }
46
+ }
47
+ if (r.gate_checks === null || typeof r.gate_checks !== 'object') {
48
+ errors.push({ code: 'RISK-001', message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
49
+ }
50
+ if (!('valid_to' in r) || !(typeof r.valid_to === 'string' || r.valid_to === null)) {
51
+ errors.push({ code: 'RISK-001', message: 'valid_to is required (an ISO date string or null).', path: 'valid_to' });
52
+ }
53
+ // likelihood / impact / residual — required (RISK-001) + enum (RISK-002).
54
+ for (const f of ['likelihood', 'impact', 'residual']) {
55
+ const v = r[f];
56
+ if (v === undefined || v === null || v === '') {
57
+ errors.push({ code: 'RISK-001', message: `${f} is required.`, path: f });
58
+ }
59
+ else if (!RISK_LEVELS.includes(v)) {
60
+ errors.push({ code: 'RISK-002', message: `${f} "${String(v)}" must be one of ${RISK_LEVELS.join(', ')}.`, path: f });
61
+ }
62
+ }
63
+ // threatens — required non-empty list (RISK-001), each entry resolves (RISK-003).
64
+ const threatens = r.threatens;
65
+ if (!Array.isArray(threatens) || threatens.length === 0) {
66
+ errors.push({ code: 'RISK-001', message: 'threatens is required and must be a non-empty list of typed IDs.', path: 'threatens' });
67
+ }
68
+ else {
69
+ threatens.forEach((ref, i) => {
70
+ const type = typeOfId(ref);
71
+ if (!type) {
72
+ errors.push({ code: 'RISK-003', message: `threatens[${i}] "${String(ref)}" is not a resolvable typed ID.`, path: `threatens[${i}]` });
73
+ return;
74
+ }
75
+ if (options.catalog && options.catalog.typeOf(ref) === undefined) {
76
+ errors.push({ code: 'RISK-003', message: `threatens[${i}] "${String(ref)}" does not resolve to an admitted element.`, path: `threatens[${i}]` });
77
+ }
78
+ });
79
+ }
80
+ // treated_by — optional list; each entry must resolve to REQUIREMENT/CONSTRAINT (RISK-004).
81
+ const treatedBy = r.treated_by;
82
+ if (treatedBy !== undefined) {
83
+ if (!Array.isArray(treatedBy)) {
84
+ errors.push({ code: 'RISK-001', message: 'treated_by must be a list of typed IDs.', path: 'treated_by' });
85
+ }
86
+ else {
87
+ treatedBy.forEach((ref, i) => {
88
+ const type = typeOfId(ref);
89
+ if (!type || !TREATED_BY_TYPES.includes(type)) {
90
+ errors.push({ code: 'RISK-004', message: `treated_by[${i}] "${String(ref)}" must resolve to a REQUIREMENT or CONSTRAINT.`, path: `treated_by[${i}]` });
91
+ return;
92
+ }
93
+ if (options.catalog && options.catalog.typeOf(ref) === undefined) {
94
+ errors.push({ code: 'RISK-004', message: `treated_by[${i}] "${String(ref)}" does not resolve to an admitted artefact.`, path: `treated_by[${i}]` });
95
+ }
96
+ });
97
+ }
98
+ }
99
+ // RISK-COVERAGE-001 (warning) — untreated risk; single-file check, no catalogue needed.
100
+ if (!Array.isArray(treatedBy) || treatedBy.length === 0) {
101
+ warnings.push({
102
+ code: 'RISK-COVERAGE-001',
103
+ message: 'treated_by is empty or absent — this risk has no recorded treatment obligation.',
104
+ path: 'treated_by',
105
+ });
106
+ }
107
+ return { valid: errors.length === 0, errors, warnings };
108
+ }
@@ -4,13 +4,16 @@
4
4
  *
5
5
  * Source of truth: the methodology `methodology_version`, declared in an adopter
6
6
  * repository's `transitrix.yaml` per the methodology `notations/MANIFEST.md`
7
- * (single source of truth for a repo's conformance). The current methodology
8
- * release is **0.5.0**.
7
+ * (single source of truth for a repo's conformance).
8
+ *
9
+ * This is the release this build *targets*, not the newest release that exists —
10
+ * the methodology may be ahead. Raise it only together with the vocabulary and
11
+ * rule coverage that release requires, so the two never disagree. Individual
12
+ * hardcoded vocabulary literals may still lag the declared release; the
13
+ * per-module drift check is what makes such a gap visible, not this constant.
9
14
  *
10
15
  * This constant is kept in lockstep with the project manifest's
11
16
  * `transitrix.methodologyVersion` (`package.json`); the
12
- * `tests/schema-version.test.ts` unit test asserts the two are equal. A CI guard
13
- * that additionally asserts both equal the methodology's published SoT lands
14
- * separately (SV-1 PR2) — do not bundle it here.
17
+ * `tests/schema-version.test.ts` unit test asserts the two are equal.
15
18
  */
16
- export declare const SCHEMA_VERSION = "0.5.0";
19
+ export declare const SCHEMA_VERSION = "3.1.0";
@@ -4,13 +4,16 @@
4
4
  *
5
5
  * Source of truth: the methodology `methodology_version`, declared in an adopter
6
6
  * repository's `transitrix.yaml` per the methodology `notations/MANIFEST.md`
7
- * (single source of truth for a repo's conformance). The current methodology
8
- * release is **0.5.0**.
7
+ * (single source of truth for a repo's conformance).
8
+ *
9
+ * This is the release this build *targets*, not the newest release that exists —
10
+ * the methodology may be ahead. Raise it only together with the vocabulary and
11
+ * rule coverage that release requires, so the two never disagree. Individual
12
+ * hardcoded vocabulary literals may still lag the declared release; the
13
+ * per-module drift check is what makes such a gap visible, not this constant.
9
14
  *
10
15
  * This constant is kept in lockstep with the project manifest's
11
16
  * `transitrix.methodologyVersion` (`package.json`); the
12
- * `tests/schema-version.test.ts` unit test asserts the two are equal. A CI guard
13
- * that additionally asserts both equal the methodology's published SoT lands
14
- * separately (SV-1 PR2) — do not bundle it here.
17
+ * `tests/schema-version.test.ts` unit test asserts the two are equal.
15
18
  */
16
- export const SCHEMA_VERSION = '0.5.0';
19
+ export const SCHEMA_VERSION = '3.1.0';
@@ -99,7 +99,7 @@ function shellCss() {
99
99
  const cv = CSS_VAR;
100
100
  const t = TYPOGRAPHY;
101
101
  // Full-height flex chain lifted from blocks-preview / activities-preview
102
- // into the shared shell (per strategy hub #35). Body is a flex column
102
+ // into the shared shell. Body is a flex column
103
103
  // sized to the iframe; #canvas takes the remaining height with its own
104
104
  // scroll region. Without this, #canvas was content-height and any
105
105
  // overflow-x scrollbar landed mid-panel with empty space below it — the
@@ -162,7 +162,8 @@ ${levelRules}
162
162
  .tree-maturity-5{fill:var(${cv.treeMaturity5});}
163
163
  .tree-collapse-btn{cursor:pointer;fill:white;stroke:var(${cv.nodeStroke});stroke-width:1.5;}
164
164
  .tree-collapse-btn:hover{fill:var(${cv.bgElevated});}
165
- .tree-collapse-lbl{fill:var(${cv.textSecondary});font-family:${t.fontFamily};font-size:12px;font-weight:700;dominant-baseline:central;pointer-events:none;}`;
165
+ .tree-collapse-lbl{fill:var(${cv.textSecondary});font-family:${t.fontFamily};font-size:12px;font-weight:700;dominant-baseline:central;pointer-events:none;}
166
+ .blocks-grid-border{fill:none;stroke:var(${cv.border});}`;
166
167
  }
167
168
  /**
168
169
  * Generates a self-contained CSS block for embedding inside a standalone SVG file.
@@ -0,0 +1,4 @@
1
+ export type { Validation, ValidationMethod, ValidationOutcome } from './types.js';
2
+ export { VALIDATION_METHODS, VALIDATION_OUTCOMES, CLOSED_VALIDATION_OUTCOMES } from './types.js';
3
+ export { validateValidation } from './validate.js';
4
+ export type { ValidationValidateOptions } from './validate.js';
@@ -0,0 +1,2 @@
1
+ export { VALIDATION_METHODS, VALIDATION_OUTCOMES, CLOSED_VALIDATION_OUTCOMES } from './types.js';
2
+ export { validateValidation } from './validate.js';
@@ -0,0 +1,31 @@
1
+ import type { GateChecks } from '../requirement/types.js';
2
+ import type { Evidence } from '../assertion/types.js';
3
+ /** Validation method vocabulary (28-validation.md §3). */
4
+ export type ValidationMethod = 'user_acceptance' | 'field_trial' | 'stakeholder_review' | 'usability_study';
5
+ export declare const VALIDATION_METHODS: readonly ValidationMethod[];
6
+ /** Pass/fail judgement vocabulary (28-validation.md §3). */
7
+ export type ValidationOutcome = 'pass' | 'fail' | 'inconclusive' | 'not_yet_run';
8
+ export declare const VALIDATION_OUTCOMES: readonly ValidationOutcome[];
9
+ /** Outcomes that count as "closed" — the trace link has resolved one way or
10
+ * the other, distinct from still-open (`not_yet_run` / `inconclusive`)
11
+ * (28-validation.md §5, NEED-VALIDATION-COVERAGE-002). */
12
+ export declare const CLOSED_VALIDATION_OUTCOMES: readonly ValidationOutcome[];
13
+ export interface Validation {
14
+ notation: 'validation';
15
+ id: string;
16
+ /** Typed ID of the NEED this validation targets. */
17
+ validates: string;
18
+ method: ValidationMethod;
19
+ protocol: string;
20
+ result?: string;
21
+ outcome: ValidationOutcome;
22
+ evidence?: Evidence[];
23
+ performed_at?: string;
24
+ performed_by?: string;
25
+ zone: 'canon';
26
+ admitted_at: string;
27
+ admitted_by: string;
28
+ gate_checks: GateChecks;
29
+ valid_from: string;
30
+ valid_to: string | null;
31
+ }
@@ -0,0 +1,21 @@
1
+ // VALIDATION — validation-domain claim against a NEED.
2
+ // Schema: methodology notations/elements/28-validation.md §2.
3
+ //
4
+ // VALIDATION is the validation-domain counterpart to VERIFICATION (same claim
5
+ // shape, anchored one layer further upstream on NEED instead of REQUIREMENT).
6
+ export const VALIDATION_METHODS = [
7
+ 'user_acceptance',
8
+ 'field_trial',
9
+ 'stakeholder_review',
10
+ 'usability_study',
11
+ ];
12
+ export const VALIDATION_OUTCOMES = [
13
+ 'pass',
14
+ 'fail',
15
+ 'inconclusive',
16
+ 'not_yet_run',
17
+ ];
18
+ /** Outcomes that count as "closed" — the trace link has resolved one way or
19
+ * the other, distinct from still-open (`not_yet_run` / `inconclusive`)
20
+ * (28-validation.md §5, NEED-VALIDATION-COVERAGE-002). */
21
+ export const CLOSED_VALIDATION_OUTCOMES = ['pass', 'fail'];
@@ -0,0 +1,7 @@
1
+ import type { ValidationResult } from '../validation-types.js';
2
+ import { type CanonCatalog } from '../typed-id.js';
3
+ export interface ValidationValidateOptions {
4
+ /** When provided, the resolution rules enforce artefact existence. */
5
+ catalog?: CanonCatalog;
6
+ }
7
+ export declare function validateValidation(input: unknown, options?: ValidationValidateOptions): ValidationResult;
@@ -0,0 +1,106 @@
1
+ // VALIDATION validator — methodology notations/elements/28-validation.md §5.
2
+ //
3
+ // Implements VALID-001..006. The shared HDR-/LIFECYCLE- rules and the
4
+ // cross-cutting NEED-VALIDATION-COVERAGE-001/002 reverse-trace rules are
5
+ // owned elsewhere (CONTRACT.md §8) and are out of scope for this
6
+ // single-artefact validator — same posture as `validateVerification`
7
+ // (../verification/validate.ts), which VALIDATION mirrors one layer upstream
8
+ // (anchored on NEED instead of REQUIREMENT).
9
+ //
10
+ // Resolution rules (VALID-002/005) that need artefact *existence* run only
11
+ // when a `CanonCatalog` is supplied; the TYPE check VALID-002 also carries is
12
+ // derivable from the id prefix and runs either way.
13
+ import { typeOfId, isCanonicalIdOfType } from '../typed-id.js';
14
+ import { VALIDATION_METHODS, VALIDATION_OUTCOMES } from './types.js';
15
+ export function validateValidation(input, options = {}) {
16
+ const errors = [];
17
+ const warnings = [];
18
+ const { catalog } = options;
19
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
20
+ errors.push({ code: 'VALID-001', message: 'Validation must be a YAML mapping.' });
21
+ return { valid: false, errors, warnings };
22
+ }
23
+ const v = input;
24
+ // ── VALID-001 — id grammar + plain required fields ───────────────────────
25
+ if (!isCanonicalIdOfType(v.id, 'VALIDATION')) {
26
+ errors.push({ code: 'VALID-001', message: `id "${String(v.id)}" must match VALIDATION-[<middle>-]<INTEGER>.`, path: 'id' });
27
+ }
28
+ if (v.notation !== 'validation') {
29
+ errors.push({ code: 'VALID-001', message: 'notation must be the fixed value "validation".', path: 'notation' });
30
+ }
31
+ if (v.zone !== 'canon') {
32
+ errors.push({ code: 'VALID-001', message: 'zone is required and must be "canon".', path: 'zone' });
33
+ }
34
+ for (const f of ['admitted_at', 'admitted_by', 'valid_from', 'protocol']) {
35
+ if (typeof v[f] !== 'string' || v[f].trim() === '') {
36
+ errors.push({ code: 'VALID-001', message: `${f} is required.`, path: f });
37
+ }
38
+ }
39
+ if (v.gate_checks === null || typeof v.gate_checks !== 'object') {
40
+ errors.push({ code: 'VALID-001', message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
41
+ }
42
+ if (!('valid_to' in v) || !(typeof v.valid_to === 'string' || v.valid_to === null)) {
43
+ errors.push({ code: 'VALID-001', message: 'valid_to is required (an ISO date string or null).', path: 'valid_to' });
44
+ }
45
+ // ── VALID-002 — validates → NEED ─────────────────────────────────────────
46
+ const validates = v.validates;
47
+ if (typeof validates !== 'string' || validates.trim() === '') {
48
+ errors.push({ code: 'VALID-002', message: 'validates is required and must be a typed NEED id.', path: 'validates' });
49
+ }
50
+ else if (catalog) {
51
+ const t = catalog.typeOf(validates);
52
+ if (t === undefined) {
53
+ errors.push({ code: 'VALID-002', message: `validates "${validates}" does not resolve to an admitted artefact.`, path: 'validates' });
54
+ }
55
+ else if (t !== 'NEED') {
56
+ errors.push({ code: 'VALID-002', message: `validates "${validates}" resolves to a ${t}, not a NEED.`, path: 'validates' });
57
+ }
58
+ }
59
+ else if (typeOfId(validates) !== 'NEED') {
60
+ errors.push({ code: 'VALID-002', message: `validates "${validates}" must be a NEED typed id.`, path: 'validates' });
61
+ }
62
+ // ── VALID-003 — method enum ───────────────────────────────────────────────
63
+ const method = v.method;
64
+ if (method === undefined || method === null) {
65
+ errors.push({ code: 'VALID-001', message: 'method is required.', path: 'method' });
66
+ }
67
+ else if (!VALIDATION_METHODS.includes(method)) {
68
+ errors.push({ code: 'VALID-003', message: `method "${String(method)}" must be one of ${VALIDATION_METHODS.join(', ')}.`, path: 'method' });
69
+ }
70
+ // ── VALID-004 — outcome enum ──────────────────────────────────────────────
71
+ const outcome = v.outcome;
72
+ if (outcome === undefined || outcome === null) {
73
+ errors.push({ code: 'VALID-001', message: 'outcome is required.', path: 'outcome' });
74
+ }
75
+ else if (!VALIDATION_OUTCOMES.includes(outcome)) {
76
+ errors.push({ code: 'VALID-004', message: `outcome "${String(outcome)}" must be one of ${VALIDATION_OUTCOMES.join(', ')}.`, path: 'outcome' });
77
+ }
78
+ // ── VALID-005 — canonical_ref evidence resolves ──────────────────────────
79
+ if (v.evidence !== undefined) {
80
+ if (!Array.isArray(v.evidence)) {
81
+ errors.push({ code: 'VALID-001', message: 'evidence must be a list.', path: 'evidence' });
82
+ }
83
+ else {
84
+ v.evidence.forEach((e, i) => {
85
+ if (e === null || typeof e !== 'object')
86
+ return;
87
+ const entry = e;
88
+ if (entry.kind !== 'canonical_ref')
89
+ return;
90
+ const ref = entry.ref;
91
+ if (!typeOfId(ref)) {
92
+ errors.push({ code: 'VALID-005', message: `evidence[${i}] canonical_ref "${String(ref)}" is not a resolvable typed ID.`, path: `evidence[${i}].ref` });
93
+ }
94
+ else if (catalog && catalog.typeOf(ref) === undefined) {
95
+ errors.push({ code: 'VALID-005', message: `evidence[${i}] canonical_ref "${String(ref)}" does not resolve.`, path: `evidence[${i}].ref` });
96
+ }
97
+ });
98
+ }
99
+ }
100
+ // ── VALID-006 (warning) — pass outcome with no evidence ──────────────────
101
+ const evidenceEmpty = !Array.isArray(v.evidence) || v.evidence.length === 0;
102
+ if (evidenceEmpty && outcome === 'pass') {
103
+ warnings.push({ code: 'VALID-006', message: 'outcome "pass" has no evidence — an undefended positive claim.', path: 'evidence' });
104
+ }
105
+ return { valid: errors.length === 0, errors, warnings };
106
+ }
@@ -0,0 +1,4 @@
1
+ export type { Verification, VerificationMethod, VerificationOutcome } from './types.js';
2
+ export { VERIFICATION_METHODS, VERIFICATION_OUTCOMES, CLOSED_VERIFICATION_OUTCOMES } from './types.js';
3
+ export { validateVerification } from './validate.js';
4
+ export type { VerificationValidateOptions } from './validate.js';
@@ -0,0 +1,2 @@
1
+ export { VERIFICATION_METHODS, VERIFICATION_OUTCOMES, CLOSED_VERIFICATION_OUTCOMES } from './types.js';
2
+ export { validateVerification } from './validate.js';