@sigloch/contracts 3.3.0 → 4.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.
- package/dist/harness/index.d.ts +2 -2
- package/dist/se/action-priority.d.ts +101 -0
- package/dist/se/action-priority.js +124 -0
- package/dist/se/analysis-freshness-rules.d.ts +5 -0
- package/dist/se/analysis-freshness-rules.js +5 -5
- package/dist/se/ao-rules.d.ts +5 -39
- package/dist/se/ao-rules.js +20 -13
- package/dist/se/conformance-rules.d.ts +2 -2
- package/dist/se/conformance-rules.js +36 -30
- package/dist/se/cr-quality-rules.d.ts +2 -1
- package/dist/se/cr-quality-rules.js +9 -7
- package/dist/se/evaluate-all.d.ts +18 -3
- package/dist/se/evaluate-all.js +29 -26
- package/dist/se/fchain-quality-rules.d.ts +2 -1
- package/dist/se/fchain-quality-rules.js +8 -6
- package/dist/se/fmea-rules.d.ts +3 -11
- package/dist/se/fmea-rules.js +53 -16
- package/dist/se/format-e-parser.d.ts +14 -1
- package/dist/se/format-e-parser.js +8 -3
- package/dist/se/index.d.ts +4 -2
- package/dist/se/index.js +4 -2
- package/dist/se/metric-rules.d.ts +13 -5
- package/dist/se/metric-rules.js +23 -13
- package/dist/se/near-duplicate-rules.d.ts +2 -0
- package/dist/se/near-duplicate-rules.js +2 -2
- package/dist/se/ontology.d.ts +55 -4
- package/dist/se/ontology.js +46 -6
- package/dist/se/policy.d.ts +65 -0
- package/dist/se/policy.js +100 -0
- package/dist/se/quality-rules.d.ts +2 -1
- package/dist/se/quality-rules.js +9 -7
- package/dist/se/readiness.d.ts +9 -1
- package/dist/se/readiness.js +18 -2
- package/dist/se/rules.d.ts +37 -5
- package/dist/se/rules.js +112 -47
- package/dist/se/schema-quality-rules.d.ts +2 -1
- package/dist/se/schema-quality-rules.js +6 -4
- package/dist/se/uc-quality-rules.d.ts +2 -1
- package/dist/se/uc-quality-rules.js +10 -8
- package/dist/se/view-rules.d.ts +2 -6
- package/dist/se/view-rules.js +40 -13
- package/package.json +2 -1
package/dist/se/evaluate-all.js
CHANGED
|
@@ -10,21 +10,18 @@ import { ND_RULES, evaluateNDRules } from './near-duplicate-rules.js';
|
|
|
10
10
|
import { AO_RULES, evaluateAORules } from './ao-rules.js';
|
|
11
11
|
import { BQ_RULES, evaluateBQRules } from './quality-rules.js';
|
|
12
12
|
import { AF_RULES, evaluateAFRules } from './analysis-freshness-rules.js';
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* All prescribed rule definitions (single source of truth for the catalog).
|
|
15
|
+
*
|
|
16
|
+
* CR-SM-235: `domain` reicht mit durch — die Grundgesamtheit, ueber die eine Regel feuert.
|
|
17
|
+
* Konsumenten, die einen Anteil bilden (`se-steering`s `computeApplicable`), lesen den Nenner
|
|
18
|
+
* hier statt eine eigene Tabelle zu fuehren. Eine zweite Tabelle kann nicht hinterherhinken,
|
|
19
|
+
* wenn es keine zweite gibt.
|
|
20
|
+
*/
|
|
14
21
|
export const ALL_RULE_DEFS = [
|
|
15
|
-
...V3_RULES
|
|
16
|
-
...
|
|
17
|
-
|
|
18
|
-
...SC_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
19
|
-
...MT_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
20
|
-
...BQ_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
21
|
-
...ND_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
22
|
-
...CR_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
23
|
-
...AO_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
24
|
-
...FM_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
25
|
-
...VIEW_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
26
|
-
...AF_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
|
|
27
|
-
];
|
|
22
|
+
...V3_RULES, ...UC_RULES, ...FC_RULES, ...SC_RULES, ...MT_RULES, ...BQ_RULES,
|
|
23
|
+
...ND_RULES, ...CR_RULES, ...AO_RULES, ...FM_RULES, ...VIEW_RULES, ...AF_RULES,
|
|
24
|
+
].map(r => ({ id: r.id, name: r.name, severity: r.severity, domain: r.domain }));
|
|
28
25
|
// CR-SM-221: 'RD-' was missing — 'RD-01'.startsWith('R-') is false, so the
|
|
29
26
|
// decomposition rules ran in `default` only and never in the `se` profile.
|
|
30
27
|
const SE_PREFIXES = ['R-', 'RD-', 'UC-', 'FC-', 'SC-', 'MT-', 'CR-', 'AO-', 'FM-', 'NFR-', 'RT-', 'PH-', 'CA-', 'IO-', 'VR-', 'CL-', 'AF-'];
|
|
@@ -36,20 +33,26 @@ export function getRuleDefsForProfile(profile) {
|
|
|
36
33
|
return ALL_RULE_DEFS.filter(r => CODING_PREFIXES.some(p => r.id.startsWith(p)));
|
|
37
34
|
return ALL_RULE_DEFS;
|
|
38
35
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Evaluate all rules against a graph. Single call replaces the individual evaluator calls.
|
|
38
|
+
*
|
|
39
|
+
* CR-SM-233: `policy` ist **Pflicht und ohne Fallback** — ein Aufruf ohne Policy ist ein
|
|
40
|
+
* Typfehler, keine stille 0.7. Wer keine eigene Quelle hat (Konfiguration, Host), nimmt
|
|
41
|
+
* `DEFAULT_METRIC_POLICY` sichtbar an der Aufrufstelle.
|
|
42
|
+
*/
|
|
43
|
+
export function evaluateAllRules(graph, policy) {
|
|
41
44
|
return [
|
|
42
|
-
...evaluateRules(graph),
|
|
43
|
-
...evaluateBQRules(graph),
|
|
44
|
-
...evaluateUCRules(graph),
|
|
45
|
-
...evaluateFCRules(graph),
|
|
46
|
-
...evaluateSCRules(graph),
|
|
45
|
+
...evaluateRules(graph, policy),
|
|
46
|
+
...evaluateBQRules(graph, policy),
|
|
47
|
+
...evaluateUCRules(graph, policy),
|
|
48
|
+
...evaluateFCRules(graph, policy),
|
|
49
|
+
...evaluateSCRules(graph, policy),
|
|
47
50
|
...evaluateNDRules(graph),
|
|
48
|
-
...evaluateMTRules(graph),
|
|
49
|
-
...evaluateCRRules(graph),
|
|
50
|
-
...evaluateAORules(graph),
|
|
51
|
-
...evaluateFMRules(graph),
|
|
52
|
-
...evaluateViewRules(graph),
|
|
51
|
+
...evaluateMTRules(graph, policy),
|
|
52
|
+
...evaluateCRRules(graph, policy),
|
|
53
|
+
...evaluateAORules(graph, policy),
|
|
54
|
+
...evaluateFMRules(graph, policy),
|
|
55
|
+
...evaluateViewRules(graph, policy),
|
|
53
56
|
...evaluateAFRules(graph),
|
|
54
57
|
];
|
|
55
58
|
}
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { OntologyGraph } from './ontology.js';
|
|
5
5
|
import type { RuleDefinition, RuleViolation } from './rules.js';
|
|
6
|
+
import type { MetricPolicy } from './policy.js';
|
|
6
7
|
export declare function fc01ActorBoundary(graph: OntologyGraph): RuleViolation[];
|
|
7
8
|
export declare function fc02LeafUcHasFchain(graph: OntologyGraph): RuleViolation[];
|
|
8
9
|
export declare function fc03FchainFlat(graph: OntologyGraph): RuleViolation[];
|
|
9
10
|
export declare function fc04ActorBounded(graph: OntologyGraph): RuleViolation[];
|
|
10
11
|
export declare const FC_RULES: RuleDefinition[];
|
|
11
|
-
export declare function evaluateFCRules(graph: OntologyGraph): RuleViolation[];
|
|
12
|
+
export declare function evaluateFCRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
|
@@ -138,11 +138,13 @@ export function fc04ActorBounded(graph) {
|
|
|
138
138
|
// Aggregated
|
|
139
139
|
// ---------------------------------------------------------------------------
|
|
140
140
|
export const FC_RULES = [
|
|
141
|
-
{ id: 'FC-01', name: 'FCHAIN has actor boundary', severity: 'warning', evaluate: fc01ActorBoundary },
|
|
142
|
-
{ id: 'FC-02', name: 'Leaf UC has FCHAIN', severity: 'warning', evaluate: fc02LeafUcHasFchain },
|
|
143
|
-
{ id: 'FC-03', name: 'FCHAIN is flat', severity: 'warning', evaluate: fc03FchainFlat },
|
|
144
|
-
{ id: 'FC-04', name: 'FCHAIN actor-bounded (trigger+consumer)', severity: 'warning', evaluate: fc04ActorBounded },
|
|
141
|
+
{ id: 'FC-01', name: 'FCHAIN has actor boundary', severity: 'warning', evaluate: fc01ActorBoundary, domain: ['FCHAIN'] },
|
|
142
|
+
{ id: 'FC-02', name: 'Leaf UC has FCHAIN', severity: 'warning', evaluate: fc02LeafUcHasFchain, domain: ['UC'] },
|
|
143
|
+
{ id: 'FC-03', name: 'FCHAIN is flat', severity: 'warning', evaluate: fc03FchainFlat, domain: ['FCHAIN'] },
|
|
144
|
+
{ id: 'FC-04', name: 'FCHAIN actor-bounded (trigger+consumer)', severity: 'warning', evaluate: fc04ActorBounded, domain: ['FCHAIN'] },
|
|
145
145
|
];
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
// CR-SM-236: `policy` wird durchgereicht, auch wo diese Familie heute keine Schwelle hat —
|
|
147
|
+
// ein Sonderweg je Familie waere genau der zweite Pfad, den der Regelsatz verbietet.
|
|
148
|
+
export function evaluateFCRules(graph, policy) {
|
|
149
|
+
return FC_RULES.flatMap(rule => rule.evaluate(graph, policy));
|
|
148
150
|
}
|
package/dist/se/fmea-rules.d.ts
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CR-182: FMEA/FTA Risk Rules + NFR Budget Overshoot Detection.
|
|
3
|
-
* FM-01: Risk-REQ missing FMEA attributes (severity, occurrence, detection).
|
|
4
|
-
* FM-02: Risk-REQ without mitigation (compose→REQ(kinds∋mitigation)).
|
|
5
|
-
* FM-03: High-risk REQ (RPN>100) without passed verification.
|
|
6
|
-
* NFR-01: measured exceeds budget for an NFR dimension. CR-228 splits the target
|
|
7
|
-
* by dimension nature: physical budgets (weight/power/cost) live on the part
|
|
8
|
-
* (MOD); behavioral budgets (timing/memory-throughput) on the FCHAIN/FUNC.
|
|
9
|
-
*/
|
|
10
1
|
import type { OntologyGraph } from './ontology.js';
|
|
11
2
|
import type { RuleViolation, RuleDefinition } from './rules.js';
|
|
3
|
+
import type { MetricPolicy } from './policy.js';
|
|
12
4
|
export declare function fm01MissingFmeaAttributes(graph: OntologyGraph): RuleViolation[];
|
|
13
5
|
export declare function fm02MissingMitigation(graph: OntologyGraph): RuleViolation[];
|
|
14
|
-
export declare function fm03HighRiskUnverified(graph: OntologyGraph): RuleViolation[];
|
|
6
|
+
export declare function fm03HighRiskUnverified(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
|
15
7
|
export declare function nfr01BudgetOvershoot(graph: OntologyGraph): RuleViolation[];
|
|
16
8
|
export declare const FM_RULES: RuleDefinition[];
|
|
17
|
-
export declare function evaluateFMRules(graph: OntologyGraph): RuleViolation[];
|
|
9
|
+
export declare function evaluateFMRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
package/dist/se/fmea-rules.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CR-182: FMEA/FTA Risk Rules + NFR Budget Overshoot Detection.
|
|
3
|
+
* FM-01: Risk-REQ missing FMEA attributes (severity, occurrence, detection).
|
|
4
|
+
* FM-02: Risk-REQ without mitigation (compose→REQ(kinds∋mitigation)).
|
|
5
|
+
* FM-03: risk REQ with Action Priority High and no passed verification.
|
|
6
|
+
* NFR-01: measured exceeds budget for an NFR dimension. CR-228 splits the target
|
|
7
|
+
* by dimension nature: physical budgets (weight/power/cost) live on the part
|
|
8
|
+
* (MOD); behavioral budgets (timing/memory-throughput) on the FCHAIN/FUNC.
|
|
9
|
+
*/
|
|
10
|
+
import { TestRefsSchema } from './ontology.js';
|
|
11
|
+
import { actionPriority, apMethod } from './action-priority.js';
|
|
1
12
|
const PHYSICAL_BUDGET_PAIRS = [
|
|
2
13
|
['costBudget', 'measuredCost', 'cost'],
|
|
3
14
|
['weightBudgetKg', 'measuredWeightKg', 'weight (kg)'],
|
|
@@ -58,9 +69,17 @@ export function fm02MissingMitigation(graph) {
|
|
|
58
69
|
}));
|
|
59
70
|
}
|
|
60
71
|
// ---------------------------------------------------------------------------
|
|
61
|
-
// FM-03:
|
|
72
|
+
// FM-03: risk REQ with Action Priority High and no passed verification
|
|
73
|
+
//
|
|
74
|
+
// CR-SM-229: die Einstufung kommt aus `actionPriority()` — mit lizenzierter Tabelle die echte
|
|
75
|
+
// AIAG-VDA-Zuordnung, ohne sie der markierte Uebergang (bestaetigte Invarianten, sonst
|
|
76
|
+
// RPN-Baender). CR-SM-236: `policy.riskRpn` ist die RPN-Grenze dieses Uebergangs;
|
|
77
|
+
// `null` → messen, nicht urteilen, die Regel schweigt.
|
|
62
78
|
// ---------------------------------------------------------------------------
|
|
63
|
-
export function fm03HighRiskUnverified(graph) {
|
|
79
|
+
export function fm03HighRiskUnverified(graph, policy) {
|
|
80
|
+
const threshold = policy.riskRpn;
|
|
81
|
+
if (threshold === null)
|
|
82
|
+
return [];
|
|
64
83
|
const riskReqs = graph.elements.filter(e => e.type === 'REQ' && e.kinds?.includes('risk'));
|
|
65
84
|
return riskReqs
|
|
66
85
|
.filter(riskReq => {
|
|
@@ -69,25 +88,43 @@ export function fm03HighRiskUnverified(graph) {
|
|
|
69
88
|
const o = Number(a['occurrence']);
|
|
70
89
|
const d = Number(a['detection']);
|
|
71
90
|
if (isNaN(s) || isNaN(o) || isNaN(d))
|
|
72
|
-
return false; //
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
return false; // no ratings → nothing to classify
|
|
92
|
+
// CR-SM-229: Action Priority statt RPN. RPN irrt gerichtet — S 10 / O 2 / D 2 ergibt
|
|
93
|
+
// RPN 40 („niedrig"), waehrend AP dort immer `High` sagt: ein gutes Detection-Rating
|
|
94
|
+
// rechnet eine sicherheitskritische Schwere weg. Genau dafuer hat AIAG-VDA 2019 RPN
|
|
95
|
+
// ersetzt, nicht ergaenzt.
|
|
96
|
+
if (actionPriority(s, o, d, threshold, policy.apTable ?? undefined) !== 'High')
|
|
75
97
|
return false;
|
|
76
|
-
// Check: TEST→verify→riskReq
|
|
98
|
+
// Check: TEST→verify→riskReq, and that TEST fully passed.
|
|
99
|
+
//
|
|
100
|
+
// CR-SM-231b: „bestanden" heisst **jeder** testRefs-Eintrag ist `passed`. Bei n Laeufen
|
|
101
|
+
// waere „irgendeiner gruen" die gefaehrliche Lesart: ein gruener Unit-Lauf wuerde einen
|
|
102
|
+
// roten Visual-Lauf verdecken und ein Risiko-REQ als verifiziert ausweisen. Ein Eintrag
|
|
103
|
+
// ohne Ergebnis ist nicht bestanden — nicht gelaufen ist nicht gruen.
|
|
77
104
|
const hasPassedTest = graph.traces.some(t => t.type === 'verify' &&
|
|
78
105
|
t.target === riskReq.id &&
|
|
79
|
-
graph.elements.some(el =>
|
|
106
|
+
graph.elements.some(el => {
|
|
107
|
+
if (el.id !== t.source || el.type !== 'TEST')
|
|
108
|
+
return false;
|
|
109
|
+
const parsed = TestRefsSchema.safeParse(el.attributes?.testRefs);
|
|
110
|
+
if (!parsed.success)
|
|
111
|
+
return false; // keine Bindung → keine Evidenz
|
|
112
|
+
return parsed.data.every(ref => ref.result === 'passed');
|
|
113
|
+
}));
|
|
80
114
|
return !hasPassedTest;
|
|
81
115
|
})
|
|
82
116
|
.map(e => {
|
|
83
117
|
const a = e.attributes ?? {};
|
|
84
|
-
const
|
|
118
|
+
const s = Number(a['severity']), o = Number(a['occurrence']), d = Number(a['detection']);
|
|
119
|
+
const method = apMethod(policy.apTable ?? undefined);
|
|
120
|
+
// Der Hinweis auf das Verfahren kann nicht von der Berechnung abweichen: beide lesen
|
|
121
|
+
// dieselbe Quelle. `rpn-interim` heisst „bestaetigtes AP, wo bekannt; RPN, wo nicht".
|
|
85
122
|
return {
|
|
86
123
|
rule_id: 'FM-03',
|
|
87
124
|
severity: 'error',
|
|
88
125
|
element_id: e.id,
|
|
89
|
-
message: `${e.id} has
|
|
90
|
-
fix_hint: 'Add a TEST
|
|
126
|
+
message: `${e.id} has Action Priority High (S${s}/O${o}/D${d}, ${method}) without passed test verification`,
|
|
127
|
+
fix_hint: 'Add a TEST whose every testRefs entry has result=passed, and a verify trace to this risk REQ',
|
|
91
128
|
};
|
|
92
129
|
});
|
|
93
130
|
}
|
|
@@ -127,11 +164,11 @@ export function nfr01BudgetOvershoot(graph) {
|
|
|
127
164
|
// Aggregated array & convenience runner
|
|
128
165
|
// ---------------------------------------------------------------------------
|
|
129
166
|
export const FM_RULES = [
|
|
130
|
-
{ id: 'FM-01', name: 'RiskReqFmeaAttributes', severity: 'warning', evaluate: fm01MissingFmeaAttributes },
|
|
131
|
-
{ id: 'FM-02', name: 'RiskReqMitigation', severity: 'warning', evaluate: fm02MissingMitigation },
|
|
132
|
-
{ id: 'FM-03', name: 'HighRiskVerification', severity: 'error', evaluate: fm03HighRiskUnverified },
|
|
133
|
-
{ id: 'NFR-01', name: 'BudgetOvershoot', severity: 'warning', evaluate: nfr01BudgetOvershoot },
|
|
167
|
+
{ id: 'FM-01', name: 'RiskReqFmeaAttributes', severity: 'warning', evaluate: fm01MissingFmeaAttributes, domain: ['REQ'] },
|
|
168
|
+
{ id: 'FM-02', name: 'RiskReqMitigation', severity: 'warning', evaluate: fm02MissingMitigation, domain: ['REQ'] },
|
|
169
|
+
{ id: 'FM-03', name: 'HighRiskVerification', severity: 'error', evaluate: fm03HighRiskUnverified, domain: ['REQ'] },
|
|
170
|
+
{ id: 'NFR-01', name: 'BudgetOvershoot', severity: 'warning', evaluate: nfr01BudgetOvershoot, domain: ['FUNC'] },
|
|
134
171
|
];
|
|
135
|
-
export function evaluateFMRules(graph) {
|
|
136
|
-
return FM_RULES.flatMap(rule => rule.evaluate(graph));
|
|
172
|
+
export function evaluateFMRules(graph, policy) {
|
|
173
|
+
return FM_RULES.flatMap(rule => rule.evaluate(graph, policy));
|
|
137
174
|
}
|
|
@@ -24,7 +24,7 @@ export interface FormatEOperation {
|
|
|
24
24
|
/**
|
|
25
25
|
* CR-147: Parsed @key value attributes from lines below the node entry.
|
|
26
26
|
* Values are strings, EXCEPT JSON object/array literals which are hydrated
|
|
27
|
-
* (BOK-CR-026) — object-valued bindings like `realRef`/`
|
|
27
|
+
* (BOK-CR-026) — object- and array-valued bindings like `realRef`/`testRefs` must reach
|
|
28
28
|
* `attributes` as objects or R-26/R-19 reject them as invalid.
|
|
29
29
|
*/
|
|
30
30
|
attributes?: Record<string, unknown>;
|
|
@@ -38,6 +38,19 @@ export interface FormatEDiff {
|
|
|
38
38
|
}
|
|
39
39
|
/** Extract a ```format-e block from LLM output. Returns null if not found. */
|
|
40
40
|
export declare function extractFormatE(llmOutput: string): string | null;
|
|
41
|
+
/**
|
|
42
|
+
* BOK-CR-026: hydrate a JSON object/array attribute value. The ontology's bindings
|
|
43
|
+
* (`realRef {file,symbol?,lang?}`, `testRefs [{file,tool,…}]`) are objects/arrays; kept as raw
|
|
44
|
+
* strings they fail RealRefSchema/TestRefSchema and the element reads as unbound.
|
|
45
|
+
* Only `{…}`/`[…]` are attempted — every other value stays the string it is, and a
|
|
46
|
+
* malformed literal falls back to the string rather than failing the whole parse.
|
|
47
|
+
*
|
|
48
|
+
* CR-GC-334: exported, because `FormatECodec` (graph-api-core) parses the SAME `@key value`
|
|
49
|
+
* lines and did NOT hydrate — the identical defect this function was written for, one
|
|
50
|
+
* package over. Two hydration rules would drift; there is one, and it lives here with the
|
|
51
|
+
* schemas it feeds.
|
|
52
|
+
*/
|
|
53
|
+
export declare function hydrateAttrValue(raw: string): unknown;
|
|
41
54
|
export interface ParseFormatEOptions {
|
|
42
55
|
/**
|
|
43
56
|
* CR-SM-216: resolve the type of a uid that this text does not declare. A mutation
|
|
@@ -44,12 +44,17 @@ const NODE_RE = /^([+\-~!])?\s*(\S+?)(?:\|(.*))?$/;
|
|
|
44
44
|
const ATTR_RE = /^\s*@(\w+)\s+(.+)$/;
|
|
45
45
|
/**
|
|
46
46
|
* BOK-CR-026: hydrate a JSON object/array attribute value. The ontology's bindings
|
|
47
|
-
* (`realRef {file,symbol?,lang?}`, `
|
|
47
|
+
* (`realRef {file,symbol?,lang?}`, `testRefs [{file,tool,…}]`) are objects/arrays; kept as raw
|
|
48
48
|
* strings they fail RealRefSchema/TestRefSchema and the element reads as unbound.
|
|
49
49
|
* Only `{…}`/`[…]` are attempted — every other value stays the string it is, and a
|
|
50
50
|
* malformed literal falls back to the string rather than failing the whole parse.
|
|
51
|
+
*
|
|
52
|
+
* CR-GC-334: exported, because `FormatECodec` (graph-api-core) parses the SAME `@key value`
|
|
53
|
+
* lines and did NOT hydrate — the identical defect this function was written for, one
|
|
54
|
+
* package over. Two hydration rules would drift; there is one, and it lives here with the
|
|
55
|
+
* schemas it feeds.
|
|
51
56
|
*/
|
|
52
|
-
function hydrateAttrValue(raw) {
|
|
57
|
+
export function hydrateAttrValue(raw) {
|
|
53
58
|
if (!/^[{[]/.test(raw))
|
|
54
59
|
return raw;
|
|
55
60
|
try {
|
|
@@ -267,7 +272,7 @@ export function serializeToFormatE(graph) {
|
|
|
267
272
|
for (const [k, v] of Object.entries(el.attributes)) {
|
|
268
273
|
if (v == null)
|
|
269
274
|
continue;
|
|
270
|
-
// BOK-CR-026: objects/arrays as JSON — String({}) collapses a realRef/
|
|
275
|
+
// BOK-CR-026: objects/arrays as JSON — String({}) collapses a realRef/testRefs
|
|
271
276
|
// binding to "[object Object]" and loses it on the next parse.
|
|
272
277
|
const text = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
273
278
|
if (text.length > 0)
|
package/dist/se/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Single source of truth for SE ontology schemas across all projects.
|
|
4
4
|
*/
|
|
5
5
|
/** Ontology schema version (element types + trace types). */
|
|
6
|
-
export declare const ONTOLOGY_VERSION = "
|
|
6
|
+
export declare const ONTOLOGY_VERSION = "6.0.0";
|
|
7
7
|
/** Rules engine version (validation rules incl. RC conformance). */
|
|
8
|
-
export declare const RULES_VERSION = "2.
|
|
8
|
+
export declare const RULES_VERSION = "2.27.0";
|
|
9
9
|
/** Meta-model version (trace pattern constraints + format-e parser). */
|
|
10
10
|
export declare const META_MODEL_VERSION = "1.4.0";
|
|
11
11
|
export * from './ontology.js';
|
|
@@ -15,6 +15,8 @@ export * from './schema-quality-rules.js';
|
|
|
15
15
|
export * from './uc-quality-rules.js';
|
|
16
16
|
export * from './fchain-quality-rules.js';
|
|
17
17
|
export * from './metric-rules.js';
|
|
18
|
+
export * from './policy.js';
|
|
19
|
+
export * from './action-priority.js';
|
|
18
20
|
export * from './fmea-rules.js';
|
|
19
21
|
export * from './view-rules.js';
|
|
20
22
|
export * from './cr-quality-rules.js';
|
package/dist/se/index.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Single source of truth for SE ontology schemas across all projects.
|
|
4
4
|
*/
|
|
5
5
|
/** Ontology schema version (element types + trace types). */
|
|
6
|
-
export const ONTOLOGY_VERSION = '
|
|
6
|
+
export const ONTOLOGY_VERSION = '6.0.0'; // BREAKING (CR-SM-231b): das knotenweite `testResult` entfaellt — das Ergebnis haengt PRO `testRefs`-Eintrag (`result`, `ranAt`, `evidence`), aus demselben Grund wie `tool`. Ein einzelnes Ergebnis am Knoten konnte bei n Laeufen nicht sagen, welcher gemeint ist, und "einer rot, einer gruen" war gar nicht darstellbar — genau der Zustand, den ein Gate wissen muss. FM-03 liest jetzt "jeder Eintrag passed": "irgendeiner gruen" haette einen gruenen Unit-Lauf einen roten Visual-Lauf verdecken lassen. Ein Eintrag ohne Ergebnis ist nicht bestanden. VR-01 meldet die Dateien ohne Ergebnis statt nur den Knoten. Prior: BREAKING (CR-SM-231): `testRef` (Objekt) entfaellt ersatzlos zugunsten von `testRefs` (Array, min 1) — eine Abnahme, n Testdateien. Kein Union, kein Alias: ein Graph mit dem alten Attribut faellt R-19 zur Last und muss migriert werden. Anlass war ein Zaehl-Audit (537 laufende Tests in 67 Dateien, 14 TEST-Knoten mit je genau einer Datei, 53 Dateien an keine Abnahme gebunden) plus ein belegter Ausweichweg: dieselbe Spec-Datei stand im testRef ZWEIER TEST-Knoten, womit die Relation faktisch n:m war — ein roter Lauf keiner Abnahme mehr eindeutig zuordenbar, der TRR-Gate zaehlte dieselbe Evidenz doppelt. `tool` bleibt PRO EINTRAG: eine Abnahme mischt real die Runner (vitest + playwright). +AttributeSpec.type 'array' (testRefs ist das erste Listen-Attribut). Prior: BREAKING: `SemanticId` (`Name.TypeAbbr.Counter`) deleted, `ElementUid` (`<TYPE>-<slug>`) is the family canon — the old canon was used by no production graph of the family while 626 of 1145 elements already carried TYPE-slug (CR-SM-217); realRef unifies codeRef+schemaRef (+physical-MOD CAD ref), symbol optional; testRef stays separate (CR-228 C); +RepoRelativePathSchema on testRef/realRef .file — no absolute/`..` paths (CR-GC-255)
|
|
7
7
|
/** Rules engine version (validation rules incl. RC conformance). */
|
|
8
|
-
export const RULES_VERSION = '2.
|
|
8
|
+
export const RULES_VERSION = '2.27.0'; // CR-SM-239: AF-01..05 und R-28 deklarieren `domain: ['graph']` statt `['SYS']` — sie pruefen EINMAL den Graphen, nicht die SYS-Elemente. Als Ein-Element-Gruppe waren sie ein Nenner-Beitrag mit fast sicherem Verstoss und zogen jede sonst leere Dimension auf 0 %: ein Graph ohne eine einzige REQ las `req` = 0 % (1 - 2/2 aus AF-01/AF-03) statt „nichts zu messen", und die Fokuswahl schickte den Executor dorthin. Kein Regelverhalten geaendert — nur die deklarierte Grundgesamtheit. Prior: CR-SM-231: +R-29 Testdatei-Exklusivitaet (severity **error**) — jede Testdatei erscheint in hoechstens einem `testRefs`. Das ist die Haelfte, die 1:n ERZWINGT statt es nur zu erlauben; ohne sie driftet das Attribut zurueck nach n:m. Bewusst schaerfer als R-19/R-20 (beide warning): eine doppelt beanspruchte Datei macht Gate-Zahlen nachweislich falsch, das ist eine Fehlmessung und kein Vollstaendigkeits-Signal. Rein graph-strukturell, kein I/O. R-19 und RC-02 lesen `testRefs`; RC-02 iteriert die Eintraege und nennt den konkreten Pfad statt nur der Knoten-ID. Prior: CR-SM-236: die letzten drei Urteilsschwellen sind Policy-Parameter statt Literal — CR-01 (`crossingFlows`, erstmals mit Aus-Zustand: `null` unterdrueckt auch die info je Modulpaar, die bisher die arch-Dimension verduennte), FM-03 (`riskRpn`, vorher inline 100) und R-04 (`moduleSize.{large,coupled,crossings}`, vorher inline 12/8/2 — drei Urteile, nicht eins). R-04 heisst jetzt 'Module size relative to crossing flows': die Regel waegt Groesse GEGEN Kreuzungen ab, der alte Name 'Max module size' verschwieg die zweite Haelfte der Bedingung. `RuleDefinition.evaluate` nimmt die Policy als zweiten Parameter, damit keine Familie einen Sonderweg braucht; einstellige Regelfunktionen bleiben zuweisbar. Bewertung unter DEFAULT_METRIC_POLICY unveraendert. Prior: CR-GC-315: R-12 + R-21 no longer tax FLOW reuse. R-12 restricted to dependency-carrying traces (compose/allocate/relation) — on `io` the only reachable shape was FUNC ─io→ FLOW ─io→ the SAME FUNC, i.e. read-modify-write on a shared FLOW, so the check was pure false-positive there (real io-cycles span ≥2 FUNCs and a 2-cycle test cannot see them); satisfy/verify/produces 2-cycles are pattern-illegal and belong to R-18. Its dedup key is now direction-independent (`type|sorted pair`) — keying on the message never collapsed anything, so every cycle was reported twice. R-21 no longer derives FUNC↔FUNC connections from FLOW co-adjacency alone: a producer/consumer pair with NO shared FCHAIN is silent. One hub FLOW with P producers and C consumers manufactured P·C findings, each demanding its own FCHAIN+integration test including pairs that never interact — reuse was penalised quadratically. The FCHAIN is the declared integration scope; the test is owed on that declared claim only. Rule intent (CR-GC-240 gap: unit/UC tests do not cover FUNC↔FUNC wiring) unchanged. Prior: CR-SM-227: +AF-01..05 Analysis-Freshness-Legs (analysis-freshness-rules.ts) — the third leg-kind a review gate checks (rule legs, layer-presence legs [R-28], now analysis-freshness legs, docs/articles/07-the-scoring-landscape.md); presence-only rules (Presence/Resolution-Split like R-19/R-20/R-26/R-27 vs. RC-01..05) checking a `graphVersion` freshness stamp exists under SYS.attributes.analysisFreshness.<AnalysisArtifactId> for each of the 5 CR-GC-221 judgment artifacts (conops/trade/assumption-review/fmea/implplan) — staleness (stamp vs live graphVersion) stays a consumer/I-O concern (`CreationCurrencyProvider`, @sigloch/graphcode-client), NOT evaluated here; Familie-Review 2026-08-05 gate assignment → RULE_TO_PHASE: ConOps/Trade/Assumption-Review → PDR, FMEA → CDR, Implementation Plan → TRR (SRR gets none); +AnalysisArtifactId enum + AnalysisFreshnessStampSchema (ontology.ts) as the SSOT graphcode-client's ARTIFACT_CATALOG analysis ids must match; grober Graph-Versions-Stempel only, no scope-hash in this first cut (conscious CR-SM-227 limitation).
|
|
9
9
|
/** Meta-model version (trace pattern constraints + format-e parser). */
|
|
10
10
|
export const META_MODEL_VERSION = '1.4.0'; // -REQ→MOD allocate pattern removed (CR-228 A); +FUNC→FUNC compose (blackbox function decomposition)
|
|
11
11
|
export * from './ontology.js';
|
|
@@ -15,6 +15,8 @@ export * from './schema-quality-rules.js';
|
|
|
15
15
|
export * from './uc-quality-rules.js';
|
|
16
16
|
export * from './fchain-quality-rules.js';
|
|
17
17
|
export * from './metric-rules.js';
|
|
18
|
+
export * from './policy.js';
|
|
19
|
+
export * from './action-priority.js';
|
|
18
20
|
export * from './fmea-rules.js';
|
|
19
21
|
export * from './view-rules.js';
|
|
20
22
|
export * from './cr-quality-rules.js';
|
|
@@ -4,20 +4,26 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { OntologyGraph } from './ontology.js';
|
|
6
6
|
import type { RuleViolation } from './rules.js';
|
|
7
|
+
import type { MetricPolicy } from './policy.js';
|
|
7
8
|
/**
|
|
8
9
|
* MT-01: Module Instability (CR-165: indirect via allocate-path).
|
|
9
|
-
* I = fan_out / (fan_in + fan_out) >
|
|
10
|
+
* I = fan_out / (fan_in + fan_out) > `policy.instability` → warning.
|
|
10
11
|
* fan_out = traces from FUNCs-in-module pointing to elements OUTSIDE the module.
|
|
11
12
|
* fan_in = traces from OUTSIDE pointing to FUNCs-in-module.
|
|
12
13
|
* Direct MOD→MOD io/compose traces also count.
|
|
14
|
+
*
|
|
15
|
+
* CR-SM-233: die Schwelle ist Eingabe, nicht Konstante — `policy.instability === null`
|
|
16
|
+
* heißt messen, nicht urteilen (`moduleMetrics` liefert den Wert unverändert weiter).
|
|
13
17
|
*/
|
|
14
|
-
export declare function mt01Instability(graph: OntologyGraph): RuleViolation[];
|
|
18
|
+
export declare function mt01Instability(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
|
15
19
|
/**
|
|
16
20
|
* MT-02: LCOM4 (Lack of Cohesion — component count).
|
|
17
21
|
* MOD with allocated FUNCs that share no common io/satisfy targets → cohesion problem.
|
|
18
|
-
*
|
|
22
|
+
* `policy.lcom4.info` ≤ LCOM4 < `policy.lcom4.warning` → info, darüber warning.
|
|
23
|
+
*
|
|
24
|
+
* CR-SM-233: die Stufen sind Eingabe, `null` heißt messen statt urteilen.
|
|
19
25
|
*/
|
|
20
|
-
export declare function mt02Lcom4(graph: OntologyGraph): RuleViolation[];
|
|
26
|
+
export declare function mt02Lcom4(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
|
21
27
|
/** One module's allocation-cohesion measurement (CR-SM-223). */
|
|
22
28
|
export interface AllocationCohesion {
|
|
23
29
|
moduleId: string;
|
|
@@ -92,10 +98,12 @@ export declare const MT_RULES: readonly [{
|
|
|
92
98
|
readonly name: "Module instability";
|
|
93
99
|
readonly severity: "warning";
|
|
94
100
|
readonly evaluate: typeof mt01Instability;
|
|
101
|
+
readonly domain: readonly ["MOD"];
|
|
95
102
|
}, {
|
|
96
103
|
readonly id: "MT-02";
|
|
97
104
|
readonly name: "Module cohesion (LCOM4)";
|
|
98
105
|
readonly severity: "info";
|
|
99
106
|
readonly evaluate: typeof mt02Lcom4;
|
|
107
|
+
readonly domain: readonly ["MOD"];
|
|
100
108
|
}];
|
|
101
|
-
export declare function evaluateMTRules(graph: OntologyGraph): RuleViolation[];
|
|
109
|
+
export declare function evaluateMTRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
package/dist/se/metric-rules.js
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
|
-
const INSTABILITY_THRESHOLD = 0.7;
|
|
2
1
|
/**
|
|
3
2
|
* MT-01: Module Instability (CR-165: indirect via allocate-path).
|
|
4
|
-
* I = fan_out / (fan_in + fan_out) >
|
|
3
|
+
* I = fan_out / (fan_in + fan_out) > `policy.instability` → warning.
|
|
5
4
|
* fan_out = traces from FUNCs-in-module pointing to elements OUTSIDE the module.
|
|
6
5
|
* fan_in = traces from OUTSIDE pointing to FUNCs-in-module.
|
|
7
6
|
* Direct MOD→MOD io/compose traces also count.
|
|
7
|
+
*
|
|
8
|
+
* CR-SM-233: die Schwelle ist Eingabe, nicht Konstante — `policy.instability === null`
|
|
9
|
+
* heißt messen, nicht urteilen (`moduleMetrics` liefert den Wert unverändert weiter).
|
|
8
10
|
*/
|
|
9
|
-
export function mt01Instability(graph) {
|
|
11
|
+
export function mt01Instability(graph, policy) {
|
|
10
12
|
const violations = [];
|
|
13
|
+
const threshold = policy.instability;
|
|
14
|
+
if (threshold === null)
|
|
15
|
+
return violations;
|
|
11
16
|
// CR-SM-232: EINE Rechnung, zwei Ausgaben. Die fan_in/fan_out-Formel steht in
|
|
12
17
|
// `measureModules` — hier wird nur noch geschwellt. Sonst stünde die Formel
|
|
13
18
|
// doppelt im selben File und der Export wäre eine zweite Implementierung.
|
|
14
19
|
for (const m of measureModules(graph)) {
|
|
15
20
|
if (m.instability === null)
|
|
16
21
|
continue;
|
|
17
|
-
if (m.instability >
|
|
22
|
+
if (m.instability > threshold) {
|
|
18
23
|
violations.push({
|
|
19
24
|
rule_id: 'MT-01',
|
|
20
25
|
severity: 'warning',
|
|
21
26
|
element_id: m.moduleId,
|
|
22
|
-
message: `${m.moduleName} has instability ${Math.round(m.instability * 100)}% (>${
|
|
27
|
+
message: `${m.moduleName} has instability ${Math.round(m.instability * 100)}% (>${threshold * 100}%). fan_in=${m.fanIn}, fan_out=${m.fanOut}`,
|
|
23
28
|
});
|
|
24
29
|
}
|
|
25
30
|
}
|
|
@@ -28,19 +33,24 @@ export function mt01Instability(graph) {
|
|
|
28
33
|
/**
|
|
29
34
|
* MT-02: LCOM4 (Lack of Cohesion — component count).
|
|
30
35
|
* MOD with allocated FUNCs that share no common io/satisfy targets → cohesion problem.
|
|
31
|
-
*
|
|
36
|
+
* `policy.lcom4.info` ≤ LCOM4 < `policy.lcom4.warning` → info, darüber warning.
|
|
37
|
+
*
|
|
38
|
+
* CR-SM-233: die Stufen sind Eingabe, `null` heißt messen statt urteilen.
|
|
32
39
|
*/
|
|
33
|
-
export function mt02Lcom4(graph) {
|
|
40
|
+
export function mt02Lcom4(graph, policy) {
|
|
34
41
|
const violations = [];
|
|
42
|
+
const steps = policy.lcom4;
|
|
43
|
+
if (steps === null)
|
|
44
|
+
return violations;
|
|
35
45
|
// CR-SM-232: die Union-Find-Rechnung steht in `measureModules`; hier nur die Stufen.
|
|
36
46
|
for (const m of measureModules(graph)) {
|
|
37
47
|
if (m.lcom4 === null)
|
|
38
48
|
continue;
|
|
39
49
|
const message = `${m.moduleName} has LCOM4=${m.lcom4} (${m.allocatedFuncs} FUNCs in ${m.lcom4} disconnected groups)`;
|
|
40
|
-
if (m.lcom4 >=
|
|
50
|
+
if (m.lcom4 >= steps.info && m.lcom4 < steps.warning) {
|
|
41
51
|
violations.push({ rule_id: 'MT-02', severity: 'info', element_id: m.moduleId, message });
|
|
42
52
|
}
|
|
43
|
-
else if (m.lcom4
|
|
53
|
+
else if (m.lcom4 >= steps.warning) {
|
|
44
54
|
violations.push({ rule_id: 'MT-02', severity: 'warning', element_id: m.moduleId, message });
|
|
45
55
|
}
|
|
46
56
|
}
|
|
@@ -277,10 +287,10 @@ export function allocationCohesion(graph) {
|
|
|
277
287
|
}));
|
|
278
288
|
}
|
|
279
289
|
export const MT_RULES = [
|
|
280
|
-
{ id: 'MT-01', name: 'Module instability', severity: 'warning', evaluate: mt01Instability },
|
|
281
|
-
{ id: 'MT-02', name: 'Module cohesion (LCOM4)', severity: 'info', evaluate: mt02Lcom4 },
|
|
290
|
+
{ id: 'MT-01', name: 'Module instability', severity: 'warning', evaluate: mt01Instability, domain: ['MOD'] },
|
|
291
|
+
{ id: 'MT-02', name: 'Module cohesion (LCOM4)', severity: 'info', evaluate: mt02Lcom4, domain: ['MOD'] },
|
|
282
292
|
// MT-03 retired as a rule (CR-SM-223) — see `allocationCohesion` above.
|
|
283
293
|
];
|
|
284
|
-
export function evaluateMTRules(graph) {
|
|
285
|
-
return MT_RULES.flatMap(r => r.evaluate(graph));
|
|
294
|
+
export function evaluateMTRules(graph, policy) {
|
|
295
|
+
return MT_RULES.flatMap(r => r.evaluate(graph, policy));
|
|
286
296
|
}
|
|
@@ -34,11 +34,13 @@ export declare const ND_RULES: readonly [{
|
|
|
34
34
|
readonly name: "FuncNearDuplicate";
|
|
35
35
|
readonly severity: "error";
|
|
36
36
|
readonly evaluate: typeof nd01FuncNearDuplicate;
|
|
37
|
+
readonly domain: readonly ["FUNC"];
|
|
37
38
|
}, {
|
|
38
39
|
readonly id: "ND-02";
|
|
39
40
|
readonly name: "SchemaNearDuplicate";
|
|
40
41
|
readonly severity: "error";
|
|
41
42
|
readonly evaluate: typeof nd02SchemaNearDuplicate;
|
|
43
|
+
readonly domain: readonly ["SCHEMA"];
|
|
42
44
|
}];
|
|
43
45
|
/** Evaluate all near-duplicate rules. */
|
|
44
46
|
export declare function evaluateNDRules(graph: OntologyGraph): RuleViolation[];
|
|
@@ -97,8 +97,8 @@ export function nd02SchemaNearDuplicate(graph) {
|
|
|
97
97
|
// Aggregate
|
|
98
98
|
// ---------------------------------------------------------------------------
|
|
99
99
|
export const ND_RULES = [
|
|
100
|
-
{ id: 'ND-01', name: 'FuncNearDuplicate', severity: 'error', evaluate: nd01FuncNearDuplicate },
|
|
101
|
-
{ id: 'ND-02', name: 'SchemaNearDuplicate', severity: 'error', evaluate: nd02SchemaNearDuplicate },
|
|
100
|
+
{ id: 'ND-01', name: 'FuncNearDuplicate', severity: 'error', evaluate: nd01FuncNearDuplicate, domain: ['FUNC'] },
|
|
101
|
+
{ id: 'ND-02', name: 'SchemaNearDuplicate', severity: 'error', evaluate: nd02SchemaNearDuplicate, domain: ['SCHEMA'] },
|
|
102
102
|
];
|
|
103
103
|
/** Evaluate all near-duplicate rules. */
|
|
104
104
|
export function evaluateNDRules(graph) {
|
package/dist/se/ontology.d.ts
CHANGED
|
@@ -95,26 +95,72 @@ export type RepoRelativePath = z.infer<typeof RepoRelativePathSchema>;
|
|
|
95
95
|
* Runnable binding for a TEST element (CR-GC-134, ontology bump 3.4.0).
|
|
96
96
|
* Resolves a TEST node to the concrete artefact a runner can execute, enabling
|
|
97
97
|
* bottom-up selective test deduction (`graph_tests`): change → impacted TESTs →
|
|
98
|
-
* `
|
|
98
|
+
* `testRefs` → minimal selective run command.
|
|
99
99
|
* - `file` : test file path, e.g. `tests/foo.test.ts` (the runner target).
|
|
100
100
|
* - `case` : optional named case/`describe`/`it` block within the file.
|
|
101
101
|
* - `tool` : the runner, e.g. `vitest`, `playwright`, `pytest`.
|
|
102
102
|
* - `level` : optional level, e.g. `unit`, `integration`, `validation`.
|
|
103
|
-
*
|
|
103
|
+
*
|
|
104
|
+
* `tool` steht bewusst **pro Eintrag**, nicht hochgezogen: eine Abnahme mischt real die
|
|
105
|
+
* Runner — ein TEST kann aus `tests/dashboard.test.mjs` (vitest) *und*
|
|
106
|
+
* `tests/visual/dashboard-render.spec.mjs` (playwright) bestehen. Ein Runner je TEST-Knoten
|
|
107
|
+
* wäre eine Lüge, die das alte 1:1-Schema nur deshalb nicht produzierte, weil es die zweite
|
|
108
|
+
* Datei gar nicht erst zuliess.
|
|
104
109
|
*/
|
|
105
110
|
export declare const TestRefSchema: z.ZodObject<{
|
|
106
111
|
file: z.ZodString;
|
|
107
112
|
case: z.ZodOptional<z.ZodString>;
|
|
108
113
|
tool: z.ZodString;
|
|
109
114
|
level: z.ZodOptional<z.ZodString>;
|
|
115
|
+
result: z.ZodOptional<z.ZodEnum<{
|
|
116
|
+
passed: "passed";
|
|
117
|
+
failed: "failed";
|
|
118
|
+
skipped: "skipped";
|
|
119
|
+
pending: "pending";
|
|
120
|
+
}>>;
|
|
121
|
+
ranAt: z.ZodOptional<z.ZodISODateTime>;
|
|
122
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
110
123
|
}, z.core.$strip>;
|
|
111
124
|
export type TestRef = z.infer<typeof TestRefSchema>;
|
|
125
|
+
/**
|
|
126
|
+
* CR-SM-231: eine Abnahme, **n** Testdateien — 1:n, nie n:m.
|
|
127
|
+
*
|
|
128
|
+
* Vorher war `testRef` ein einzelnes Objekt: ein TEST-Knoten war an genau eine Datei bindbar.
|
|
129
|
+
* Eine Abnahme aus Unit- *und* Visual-Lauf konnte ihre Evidenz damit nicht vollstaendig
|
|
130
|
+
* deklarieren, und der Ausweichweg war belegt — dieselbe Spec-Datei stand im `testRef` zweier
|
|
131
|
+
* TEST-Knoten. Damit war die Relation faktisch n:m: ein roter Lauf war keiner Abnahme mehr
|
|
132
|
+
* eindeutig zuordenbar, waehrend der TRR-Gate dieselbe Evidenz doppelt zaehlte.
|
|
133
|
+
*
|
|
134
|
+
* **Warum n:m hier falsch ist.** n:m zwischen Abnahme und Anforderung ist bereits korrekt
|
|
135
|
+
* modelliert und in Gebrauch (`TEST -[verify]-> REQ`) — dafuer ist eine Kante da. Die Bindung
|
|
136
|
+
* an die Laufdatei ist etwas anderes: sie ist **Evidenz-Adresse**, kein Traceability-Link. Sie
|
|
137
|
+
* gehoert ins Attribut und bleibt 1:n — ein TEST kennt n Dateien, eine Datei gehoert zu
|
|
138
|
+
* hoechstens einem TEST. Die zweite Haelfte erzwingt R-29.
|
|
139
|
+
*
|
|
140
|
+
* Gespeichert unter `OntologyElement.attributes.testRefs`. Das alte `testRef` entfaellt
|
|
141
|
+
* ersatzlos — kein Union, kein Alias, keine parallelen Pfade.
|
|
142
|
+
*/
|
|
143
|
+
export declare const TestRefsSchema: z.ZodArray<z.ZodObject<{
|
|
144
|
+
file: z.ZodString;
|
|
145
|
+
case: z.ZodOptional<z.ZodString>;
|
|
146
|
+
tool: z.ZodString;
|
|
147
|
+
level: z.ZodOptional<z.ZodString>;
|
|
148
|
+
result: z.ZodOptional<z.ZodEnum<{
|
|
149
|
+
passed: "passed";
|
|
150
|
+
failed: "failed";
|
|
151
|
+
skipped: "skipped";
|
|
152
|
+
pending: "pending";
|
|
153
|
+
}>>;
|
|
154
|
+
ranAt: z.ZodOptional<z.ZodISODateTime>;
|
|
155
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
156
|
+
}, z.core.$strip>>;
|
|
157
|
+
export type TestRefs = z.infer<typeof TestRefsSchema>;
|
|
112
158
|
/**
|
|
113
159
|
* Realization binding for an element (CR-228, ontology bump 3.9.0) — unifies the
|
|
114
160
|
* byte-identical former `codeRef` (FUNC → code symbol) and `schemaRef` (SCHEMA →
|
|
115
161
|
* Zod export), and extends to MOD (physical part → CAD/geometry artefact). The
|
|
116
162
|
* *type* of the pointing element disambiguates what kind of realization it is:
|
|
117
|
-
* FUNC→code, SCHEMA→Zod-def, physical MOD→CAD. TEST keeps its own `
|
|
163
|
+
* FUNC→code, SCHEMA→Zod-def, physical MOD→CAD. TEST keeps its own `testRefs`
|
|
118
164
|
* (a TEST is not just located but *executed* — the runner is the extra value).
|
|
119
165
|
* - `file` : realization file path, e.g. `src/harness.ts`, `part.step`.
|
|
120
166
|
* - `symbol` : the realizing symbol (function/class/Zod export). Optional — a
|
|
@@ -330,7 +376,12 @@ export declare const ELEMENT_DESCRIPTIONS: Record<ElementType, string>;
|
|
|
330
376
|
export declare const MODELING_ELEMENT_TYPES: ElementType[];
|
|
331
377
|
export interface AttributeSpec {
|
|
332
378
|
key: string;
|
|
333
|
-
|
|
379
|
+
/**
|
|
380
|
+
* CR-SM-231: `array` kommt dazu — `testRefs` ist das erste Attribut, das eine Liste ist.
|
|
381
|
+
* Als `object` deklariert waere es fuer jeden Konsumenten, der diese Spezifikation liest
|
|
382
|
+
* (Format-E-Editor, Doku-Generator), formal falsch.
|
|
383
|
+
*/
|
|
384
|
+
type: 'string' | 'number' | 'boolean' | 'enum' | 'object' | 'array';
|
|
334
385
|
enumValues?: readonly string[];
|
|
335
386
|
description: string;
|
|
336
387
|
}
|