@sigloch/contracts 3.2.0 → 4.0.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 +47 -5
- package/dist/se/metric-rules.js +199 -171
- 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 +25 -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
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CR-SM-233: Urteilsschwellen der Architektur-Metriken als Eingabe, nicht als Modulkonstante.
|
|
3
|
+
*
|
|
4
|
+
* Vorher stand die Schwelle als `const INSTABILITY_THRESHOLD = 0.7` in `metric-rules.ts`.
|
|
5
|
+
* Jede Konfigurierbarkeit von außen wäre damit automatisch ein zweiter Pfad gewesen
|
|
6
|
+
* (Config-Wert neben Code-Default) — und ein stillgelegter Wert hätte still weiterurteilt,
|
|
7
|
+
* weil der Default einspringt. Deshalb: Parameter ohne Fallback.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
/**
|
|
11
|
+
* Urteilsschwellen der Architektur-Metriken. `null` = messen, nicht urteilen.
|
|
12
|
+
*
|
|
13
|
+
* `null` ist ein erstklassiger Wert, kein „aus": die Kennzahl wird weiter gerechnet,
|
|
14
|
+
* exportiert und angezeigt; es entsteht nur kein Verstoß. Das ist die MT-03-Entscheidung
|
|
15
|
+
* (CR-SM-223) verallgemeinert — der Weg, einen unvalidierten Wert stillzulegen, ohne die
|
|
16
|
+
* Zahl zu verlieren.
|
|
17
|
+
*/
|
|
18
|
+
export declare const MetricPolicySchema: z.ZodObject<{
|
|
19
|
+
instability: z.ZodNullable<z.ZodNumber>;
|
|
20
|
+
lcom4: z.ZodNullable<z.ZodObject<{
|
|
21
|
+
info: z.ZodNumber;
|
|
22
|
+
warning: z.ZodNumber;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
crossingFlows: z.ZodNullable<z.ZodObject<{
|
|
25
|
+
warning: z.ZodNumber;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
riskRpn: z.ZodNullable<z.ZodNumber>;
|
|
28
|
+
apTable: z.ZodNullable<z.ZodObject<{
|
|
29
|
+
severityBands: z.ZodArray<z.ZodObject<{
|
|
30
|
+
from: z.ZodNumber;
|
|
31
|
+
to: z.ZodNumber;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
occurrenceBands: z.ZodArray<z.ZodObject<{
|
|
34
|
+
from: z.ZodNumber;
|
|
35
|
+
to: z.ZodNumber;
|
|
36
|
+
}, z.core.$strip>>;
|
|
37
|
+
detectionBands: z.ZodArray<z.ZodObject<{
|
|
38
|
+
from: z.ZodNumber;
|
|
39
|
+
to: z.ZodNumber;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
cells: z.ZodArray<z.ZodArray<z.ZodArray<z.ZodEnum<{
|
|
42
|
+
High: "High";
|
|
43
|
+
Medium: "Medium";
|
|
44
|
+
Low: "Low";
|
|
45
|
+
}>>>>;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
moduleSize: z.ZodNullable<z.ZodObject<{
|
|
48
|
+
large: z.ZodNumber;
|
|
49
|
+
coupled: z.ZodNumber;
|
|
50
|
+
crossings: z.ZodNumber;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export type MetricPolicy = z.infer<typeof MetricPolicySchema>;
|
|
54
|
+
/**
|
|
55
|
+
* Der Startwert, sichtbar als solcher — **kein** Fallback in der Regel.
|
|
56
|
+
*
|
|
57
|
+
* Ein Aufrufer nimmt ihn bewusst oder ersetzt ihn; er steht an genau einer Stelle und ist
|
|
58
|
+
* grep-bar. Die Werte sind die bisherigen (0.7 / 4 / 6-statt-5-Grenze siehe unten) und
|
|
59
|
+
* ausdrücklich **unvalidiert** (CR-SM-223: „Validation … is deferred") — sie sind gesetzt,
|
|
60
|
+
* nicht gemessen.
|
|
61
|
+
*
|
|
62
|
+
* `lcom4.warning = 6` ist die unveränderte Alt-Semantik: vorher `>= 4 && <= 5` → info,
|
|
63
|
+
* `> 5` → warning, also warning ab 6.
|
|
64
|
+
*/
|
|
65
|
+
export declare const DEFAULT_METRIC_POLICY: MetricPolicy;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CR-SM-233: Urteilsschwellen der Architektur-Metriken als Eingabe, nicht als Modulkonstante.
|
|
3
|
+
*
|
|
4
|
+
* Vorher stand die Schwelle als `const INSTABILITY_THRESHOLD = 0.7` in `metric-rules.ts`.
|
|
5
|
+
* Jede Konfigurierbarkeit von außen wäre damit automatisch ein zweiter Pfad gewesen
|
|
6
|
+
* (Config-Wert neben Code-Default) — und ein stillgelegter Wert hätte still weiterurteilt,
|
|
7
|
+
* weil der Default einspringt. Deshalb: Parameter ohne Fallback.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { ApTableSchema } from './action-priority.js';
|
|
11
|
+
/**
|
|
12
|
+
* Urteilsschwellen der Architektur-Metriken. `null` = messen, nicht urteilen.
|
|
13
|
+
*
|
|
14
|
+
* `null` ist ein erstklassiger Wert, kein „aus": die Kennzahl wird weiter gerechnet,
|
|
15
|
+
* exportiert und angezeigt; es entsteht nur kein Verstoß. Das ist die MT-03-Entscheidung
|
|
16
|
+
* (CR-SM-223) verallgemeinert — der Weg, einen unvalidierten Wert stillzulegen, ohne die
|
|
17
|
+
* Zahl zu verlieren.
|
|
18
|
+
*/
|
|
19
|
+
export const MetricPolicySchema = z.object({
|
|
20
|
+
/** MT-01: Instabilität, ab der gewarnt wird (exklusiv). null → MT-01 feuert nie. */
|
|
21
|
+
instability: z.number().min(0).max(1).nullable(),
|
|
22
|
+
/** MT-02: LCOM4-Stufen (info ab, warning ab). null → MT-02 feuert nie. */
|
|
23
|
+
lcom4: z
|
|
24
|
+
.object({
|
|
25
|
+
info: z.number().int().min(2),
|
|
26
|
+
warning: z.number().int().min(2),
|
|
27
|
+
})
|
|
28
|
+
.nullable(),
|
|
29
|
+
/**
|
|
30
|
+
* CR-01: kreuzende io-Flows je Modulpaar, ab denen gewarnt wird (inklusiv).
|
|
31
|
+
*
|
|
32
|
+
* `null` → CR-01 meldet **nichts**, auch keine info. Das ist der Aus-Zustand, den die Regel
|
|
33
|
+
* vorher nicht hatte: sie meldete je Modulpaar mit ≥ 1 Kreuzung, und diese info-Fälle zählen
|
|
34
|
+
* in die `arch`-Dimension ein (CR-SM-236).
|
|
35
|
+
*/
|
|
36
|
+
crossingFlows: z.object({ warning: z.number().int().min(1) }).nullable(),
|
|
37
|
+
/**
|
|
38
|
+
* FM-03: RPN (severity · occurrence · detection), ab dem ein Risiko-REQ eine bestandene
|
|
39
|
+
* Verifikation braucht (exklusiv). null → FM-03 feuert nie.
|
|
40
|
+
*
|
|
41
|
+
* 100 ist Domänenstandard, aber skalenabhängig: bei anderer Belegung von S/O/D ist es die
|
|
42
|
+
* falsche Grenze.
|
|
43
|
+
*/
|
|
44
|
+
riskRpn: z.number().int().positive().nullable(),
|
|
45
|
+
/**
|
|
46
|
+
* CR-SM-229: die lizenzierte AIAG-VDA-Tabelle, wenn der Host eine hat.
|
|
47
|
+
*
|
|
48
|
+
* Sie reist im Policy-Objekt mit, **nicht** in einem zweiten Kontext-Parameter: seit
|
|
49
|
+
* CR-SM-233 ist `policy` der eine Kanal, über den eine Regel ihre Urteilsgrundlage bekommt.
|
|
50
|
+
* Ein zweiter daneben wäre genau der parallele Pfad, den der Regelsatz verbietet.
|
|
51
|
+
*
|
|
52
|
+
* `null` → der markierte Übergang gilt (bestätigte AP-Invarianten, sonst RPN-Bänder). Der
|
|
53
|
+
* Konsument lädt die Tabelle aus einer lokalen, nie eingecheckten Datei; **im Repo und im
|
|
54
|
+
* exportierten Graphen steht sie nie** (Zellwerte sind normative Wertung, keine Fakten).
|
|
55
|
+
*/
|
|
56
|
+
apTable: ApTableSchema.nullable(),
|
|
57
|
+
/**
|
|
58
|
+
* R-04: Modulgröße **gegen** Kreuzungen — die Regel wägt beides ab, ihr alter Name
|
|
59
|
+
* („Max module size") gab das nicht her. null → R-04 feuert nie.
|
|
60
|
+
*
|
|
61
|
+
* Drei Werte, weil die Regel drei Urteile fällt. Ein einzelner Schwellwert hätte zwei davon
|
|
62
|
+
* im Code gelassen — genau der Zustand, den dieser CR beseitigt.
|
|
63
|
+
*/
|
|
64
|
+
moduleSize: z
|
|
65
|
+
.object({
|
|
66
|
+
/** > `large` FUNCs: mit Kreuzungen warning, ohne Kreuzungen info („kohäsiv, nur groß"). */
|
|
67
|
+
large: z.number().int().min(1),
|
|
68
|
+
/** > `coupled` FUNCs ist die Untergrenze, ab der die Regel überhaupt hinsieht. */
|
|
69
|
+
coupled: z.number().int().min(1),
|
|
70
|
+
/** Kreuzungen, ab denen ein nur `coupled`-großes Modul warnt (exklusiv). */
|
|
71
|
+
crossings: z.number().int().min(0),
|
|
72
|
+
})
|
|
73
|
+
.nullable(),
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Der Startwert, sichtbar als solcher — **kein** Fallback in der Regel.
|
|
77
|
+
*
|
|
78
|
+
* Ein Aufrufer nimmt ihn bewusst oder ersetzt ihn; er steht an genau einer Stelle und ist
|
|
79
|
+
* grep-bar. Die Werte sind die bisherigen (0.7 / 4 / 6-statt-5-Grenze siehe unten) und
|
|
80
|
+
* ausdrücklich **unvalidiert** (CR-SM-223: „Validation … is deferred") — sie sind gesetzt,
|
|
81
|
+
* nicht gemessen.
|
|
82
|
+
*
|
|
83
|
+
* `lcom4.warning = 6` ist die unveränderte Alt-Semantik: vorher `>= 4 && <= 5` → info,
|
|
84
|
+
* `> 5` → warning, also warning ab 6.
|
|
85
|
+
*/
|
|
86
|
+
export const DEFAULT_METRIC_POLICY = {
|
|
87
|
+
instability: 0.7,
|
|
88
|
+
lcom4: { info: 4, warning: 6 },
|
|
89
|
+
// CR-SM-236: die bisherigen Literale, jetzt an einer grep-baren Stelle.
|
|
90
|
+
// `crossingFlows.warning = 3` ist die unveränderte Alt-Semantik: vorher `count > 2` → warning.
|
|
91
|
+
crossingFlows: { warning: 3 },
|
|
92
|
+
riskRpn: 100,
|
|
93
|
+
// `large`/`coupled`/`crossings` = die drei Literale aus `maxModuleSize`: vorher
|
|
94
|
+
// `funcCount <= 8` → skip, `funcCount > 12` → groß, `crossings > 2` → gekoppelt.
|
|
95
|
+
moduleSize: { large: 12, coupled: 8, crossings: 2 },
|
|
96
|
+
// CR-SM-229: kein Startwert möglich und keiner gewollt — die Tabelle steht nur im Handbook.
|
|
97
|
+
// `null` heißt hier nicht „aus", sondern „markierter Übergang": bestätigte AP-Invarianten,
|
|
98
|
+
// sonst RPN-Bänder. `apMethod()` macht das für den Leser sichtbar.
|
|
99
|
+
apTable: null,
|
|
100
|
+
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { OntologyGraph } from './ontology.js';
|
|
7
7
|
import type { RuleDefinition, RuleViolation } from './rules.js';
|
|
8
|
+
import type { MetricPolicy } from './policy.js';
|
|
8
9
|
export declare function bq01Unambiguous(graph: OntologyGraph): RuleViolation[];
|
|
9
10
|
export declare function bq02Verifiable(graph: OntologyGraph): RuleViolation[];
|
|
10
11
|
/**
|
|
@@ -25,4 +26,4 @@ export declare function bq06Conforming(graph: OntologyGraph): RuleViolation[];
|
|
|
25
26
|
export declare function bq07Complete(graph: OntologyGraph): RuleViolation[];
|
|
26
27
|
export declare const BQ_RULES: RuleDefinition[];
|
|
27
28
|
/** Run all BQ rules against a graph, returning combined violations. */
|
|
28
|
-
export declare function evaluateBQRules(graph: OntologyGraph): RuleViolation[];
|
|
29
|
+
export declare function evaluateBQRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
package/dist/se/quality-rules.js
CHANGED
|
@@ -194,13 +194,15 @@ export function bq07Complete(graph) {
|
|
|
194
194
|
// Aggregated array & convenience runner
|
|
195
195
|
// ---------------------------------------------------------------------------
|
|
196
196
|
export const BQ_RULES = [
|
|
197
|
-
{ id: 'BQ-01', name: 'Unambiguous', severity: 'warning', evaluate: bq01Unambiguous },
|
|
198
|
-
{ id: 'BQ-02', name: 'Verifiable', severity: 'warning', evaluate: bq02Verifiable },
|
|
199
|
-
{ id: 'BQ-04', name: 'Necessary', severity: 'warning', evaluate: bq04Necessary },
|
|
200
|
-
{ id: 'BQ-06', name: 'Conforming', severity: 'warning', evaluate: bq06Conforming },
|
|
201
|
-
{ id: 'BQ-07', name: 'Complete', severity: 'warning', evaluate: bq07Complete },
|
|
197
|
+
{ id: 'BQ-01', name: 'Unambiguous', severity: 'warning', evaluate: bq01Unambiguous, domain: ['REQ'] },
|
|
198
|
+
{ id: 'BQ-02', name: 'Verifiable', severity: 'warning', evaluate: bq02Verifiable, domain: ['REQ'] },
|
|
199
|
+
{ id: 'BQ-04', name: 'Necessary', severity: 'warning', evaluate: bq04Necessary, domain: ['REQ'] },
|
|
200
|
+
{ id: 'BQ-06', name: 'Conforming', severity: 'warning', evaluate: bq06Conforming, domain: ['REQ'] },
|
|
201
|
+
{ id: 'BQ-07', name: 'Complete', severity: 'warning', evaluate: bq07Complete, domain: ['REQ'] },
|
|
202
202
|
];
|
|
203
203
|
/** Run all BQ rules against a graph, returning combined violations. */
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
// CR-SM-236: `policy` wird durchgereicht, auch wo diese Familie heute keine Schwelle hat —
|
|
205
|
+
// ein Sonderweg je Familie waere genau der zweite Pfad, den der Regelsatz verbietet.
|
|
206
|
+
export function evaluateBQRules(graph, policy) {
|
|
207
|
+
return BQ_RULES.flatMap(rule => rule.evaluate(graph, policy));
|
|
206
208
|
}
|
package/dist/se/readiness.d.ts
CHANGED
|
@@ -36,6 +36,15 @@ export declare const ReadinessScore: z.ZodObject<{
|
|
|
36
36
|
ready: z.ZodBoolean;
|
|
37
37
|
}, z.core.$strip>;
|
|
38
38
|
export type ReadinessScoreType = z.infer<typeof ReadinessScore>;
|
|
39
|
+
/**
|
|
40
|
+
* CR-SM-237: `overallScore` ist weg. Es war das **ungewichtete** Mittel der acht
|
|
41
|
+
* Dimensions-Scores — `ms` (3 Regeln) zählte so viel wie `arch` (~20 Regeln über Hunderte
|
|
42
|
+
* Elemente), die Zahl bewegte sich also mit dem Größenverhältnis der Dimensionen und nicht mit
|
|
43
|
+
* dem Zustand des Modells. Gelesen hat sie ohnehin niemand: der einzige Zugriff in der Familie
|
|
44
|
+
* war eine Formprüfung (`'overallScore' in x`) im inzwischen gelöschten `weight-vector.ts`.
|
|
45
|
+
* Ein interpretierbarer Ersatz (`1 − Σviolations / Σapplicable`) kommt, wenn er einen
|
|
46
|
+
* Konsumenten hat — nicht auf Vorrat.
|
|
47
|
+
*/
|
|
39
48
|
export declare const ReadinessReport: z.ZodObject<{
|
|
40
49
|
scores: z.ZodArray<z.ZodObject<{
|
|
41
50
|
dimension: z.ZodEnum<{
|
|
@@ -53,7 +62,6 @@ export declare const ReadinessReport: z.ZodObject<{
|
|
|
53
62
|
applicable: z.ZodNumber;
|
|
54
63
|
ready: z.ZodBoolean;
|
|
55
64
|
}, z.core.$strip>>;
|
|
56
|
-
overallScore: z.ZodNumber;
|
|
57
65
|
timestamp: z.ZodISODateTime;
|
|
58
66
|
}, z.core.$strip>;
|
|
59
67
|
export type ReadinessReportType = z.infer<typeof ReadinessReport>;
|
package/dist/se/readiness.js
CHANGED
|
@@ -23,11 +23,21 @@ export const ReadinessScore = z.object({
|
|
|
23
23
|
score: z.number().min(0).max(1), // 1 - (violations / applicable)
|
|
24
24
|
violations: z.number().int(),
|
|
25
25
|
applicable: z.number().int(),
|
|
26
|
-
|
|
26
|
+
// CR-SM-235: `score >= readyThreshold`. Die Schwelle steht bewusst NICHT hier — sie ist
|
|
27
|
+
// Eingabe von `computeReadiness`, und eine Zahl im Kommentar wäre die dritte Meinung dazu.
|
|
28
|
+
ready: z.boolean(),
|
|
27
29
|
});
|
|
30
|
+
/**
|
|
31
|
+
* CR-SM-237: `overallScore` ist weg. Es war das **ungewichtete** Mittel der acht
|
|
32
|
+
* Dimensions-Scores — `ms` (3 Regeln) zählte so viel wie `arch` (~20 Regeln über Hunderte
|
|
33
|
+
* Elemente), die Zahl bewegte sich also mit dem Größenverhältnis der Dimensionen und nicht mit
|
|
34
|
+
* dem Zustand des Modells. Gelesen hat sie ohnehin niemand: der einzige Zugriff in der Familie
|
|
35
|
+
* war eine Formprüfung (`'overallScore' in x`) im inzwischen gelöschten `weight-vector.ts`.
|
|
36
|
+
* Ein interpretierbarer Ersatz (`1 − Σviolations / Σapplicable`) kommt, wenn er einen
|
|
37
|
+
* Konsumenten hat — nicht auf Vorrat.
|
|
38
|
+
*/
|
|
28
39
|
export const ReadinessReport = z.object({
|
|
29
40
|
scores: z.array(ReadinessScore),
|
|
30
|
-
overallScore: z.number().min(0).max(1),
|
|
31
41
|
timestamp: z.iso.datetime(),
|
|
32
42
|
});
|
|
33
43
|
/**
|
|
@@ -44,6 +54,9 @@ export const RULE_TO_DIMENSION = {
|
|
|
44
54
|
'RD-04': 'arch',
|
|
45
55
|
// trace/realization/allocation completeness rules (CR-228 D: previously unmapped → advisory fall-through)
|
|
46
56
|
'R-18': 'arch', 'R-19': 'ver', 'R-20': 'arch', 'R-21': 'ver',
|
|
57
|
+
// CR-SM-231: R-29 (Testdatei-Exklusivitaet) gehoert zu 'ver' wie R-19 — beide bewerten die
|
|
58
|
+
// Evidenz-Bindung einer Abnahme, R-19 ihre Praesenz, R-29 ihre Eindeutigkeit.
|
|
59
|
+
'R-29': 'ver',
|
|
47
60
|
'R-22': 'alloc', 'R-23': 'alloc', 'R-26': 'schema', 'R-27': 'arch',
|
|
48
61
|
// CR-SM-226: R-28 Ebenen-Präsenz (>1 FUNC needs FLOW+SCHEMA) is an architecture rule.
|
|
49
62
|
'R-28': 'arch',
|
|
@@ -148,6 +161,9 @@ export const RULE_TO_PHASE = {
|
|
|
148
161
|
'NFR-01': 'CDR',
|
|
149
162
|
// TRR — test readiness.
|
|
150
163
|
'R-01': 'TRR', 'R-05': 'TRR', 'R-19': 'TRR', 'R-20': 'TRR', 'R-21': 'TRR',
|
|
164
|
+
// CR-SM-231: eine doppelt beanspruchte Testdatei laesst den TRR-Gate dieselbe Evidenz
|
|
165
|
+
// doppelt zaehlen — der Befund gehoert genau an dieses Gate.
|
|
166
|
+
'R-29': 'TRR',
|
|
151
167
|
'VR-01': 'TRR',
|
|
152
168
|
'FM-03': 'TRR',
|
|
153
169
|
'CR-R02': 'TRR',
|
package/dist/se/rules.d.ts
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod/v4';
|
|
7
7
|
import type { OntologyGraph } from './ontology.js';
|
|
8
|
+
import type { MetricPolicy } from './policy.js';
|
|
8
9
|
export declare const RuleSeverity: z.ZodEnum<{
|
|
9
10
|
error: "error";
|
|
10
|
-
warning: "warning";
|
|
11
11
|
info: "info";
|
|
12
|
+
warning: "warning";
|
|
12
13
|
}>;
|
|
13
14
|
export type RuleSeverity = z.infer<typeof RuleSeverity>;
|
|
14
15
|
/** Candidate target for resolving a violation (e.g. a REQ to satisfy, a TEST to link). */
|
|
@@ -89,8 +90,8 @@ export declare const RuleViolation: z.ZodObject<{
|
|
|
89
90
|
rule_id: z.ZodString;
|
|
90
91
|
severity: z.ZodEnum<{
|
|
91
92
|
error: "error";
|
|
92
|
-
warning: "warning";
|
|
93
93
|
info: "info";
|
|
94
|
+
warning: "warning";
|
|
94
95
|
}>;
|
|
95
96
|
element_id: z.ZodString;
|
|
96
97
|
message: z.ZodString;
|
|
@@ -152,8 +153,27 @@ export interface RuleDefinition {
|
|
|
152
153
|
id: string;
|
|
153
154
|
name: string;
|
|
154
155
|
severity: 'error' | 'warning' | 'info';
|
|
155
|
-
|
|
156
|
+
/**
|
|
157
|
+
* CR-SM-236: `policy` steht jeder Regel zur Verfuegung, damit eine Urteilsschwelle nirgends
|
|
158
|
+
* als Literal im Regelcode zurueckbleibt. Regeln ohne Schwelle deklarieren den Parameter
|
|
159
|
+
* schlicht nicht — eine einstellige Funktion bleibt zuweisbar.
|
|
160
|
+
*/
|
|
161
|
+
evaluate: (graph: OntologyGraph, policy: MetricPolicy) => RuleViolation[];
|
|
162
|
+
/**
|
|
163
|
+
* CR-SM-235: die Grundgesamtheit, ueber die die Regel feuert — der Nenner ihres
|
|
164
|
+
* Readiness-Anteils. **Der Elementtyp, ueber den sie feuert, nicht das Thema, dem sie
|
|
165
|
+
* gehoert:** MS-03 („CR ohne Milestone") feuert je CR, nicht je MS.
|
|
166
|
+
*
|
|
167
|
+
* Pflichtfeld, damit ein neuer Regeleintrag ohne Grundgesamtheit den Build bricht. Vorher
|
|
168
|
+
* lag die Zuordnung als Handtabelle in einem anderen Paket (`se-steering`), 18 von 71 Regeln
|
|
169
|
+
* fehlten dort — sie erhoehten den Zaehler, nie den Nenner, und jede neue Regel senkte den
|
|
170
|
+
* Score automatisch, bis jemand die zweite Tabelle nachzog.
|
|
171
|
+
*
|
|
172
|
+
* Mehrere Typen, wo die Regel ueber mehrere feuert (RD-04: FUNC, MOD und SYS als Eltern
|
|
173
|
+
* einer Zerlegung). `['all']` = jedes Nicht-SESSION-Element (R-08/R-18 pruefen Traces).
|
|
174
|
+
*/
|
|
175
|
+
domain: readonly string[];
|
|
156
176
|
}
|
|
157
177
|
export declare const V3_RULES: RuleDefinition[];
|
|
158
|
-
/** Run all rules against a graph */
|
|
159
|
-
export declare function evaluateRules(graph: OntologyGraph): RuleViolation[];
|
|
178
|
+
/** Run all rules against a graph. CR-SM-236: `policy` ist Pflicht — wie bei `evaluateAllRules`. */
|
|
179
|
+
export declare function evaluateRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
package/dist/se/rules.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @sigloch/contracts/se — single source of truth for SE validation rules.
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod/v4';
|
|
7
|
-
import { ElementType, TraceType,
|
|
7
|
+
import { ElementType, TraceType, TestRefsSchema, RealRefSchema } from './ontology.js';
|
|
8
8
|
import { isValidTrace } from './meta-model.js';
|
|
9
9
|
export const RuleSeverity = z.enum(['error', 'warning', 'info']);
|
|
10
10
|
/** Candidate target for resolving a violation (e.g. a REQ to satisfy, a TEST to link). */
|
|
@@ -168,16 +168,26 @@ function asilIsolation(graph) {
|
|
|
168
168
|
return violations;
|
|
169
169
|
}
|
|
170
170
|
// ---------------------------------------------------------------------------
|
|
171
|
-
// R-04:
|
|
171
|
+
// R-04: Modulgroesse GEGEN Kreuzungen (nicht „max module size")
|
|
172
|
+
//
|
|
173
|
+
// CR-SM-236: die Regel waegt Groesse gegen kreuzende io-Flows ab — ein grosses Modul ohne
|
|
174
|
+
// Kreuzungen ist info („kohaesiv, nur gross"), dasselbe Modul mit Kreuzungen ist warning.
|
|
175
|
+
// Der alte Name gab das nicht her, und die drei Schwellen (8/12/2) standen inline: eine
|
|
176
|
+
// Urteilsschwelle, die sich weder per grep noch aus dem Regelnamen ablesen laesst, ist nicht
|
|
177
|
+
// ueberpruefbar. Jetzt sind es `policy.moduleSize.{coupled,large,crossings}`.
|
|
178
|
+
// `null` → messen, nicht urteilen: die Regel schweigt.
|
|
172
179
|
// ---------------------------------------------------------------------------
|
|
173
|
-
function maxModuleSize(graph) {
|
|
174
|
-
const modules = graph.elements.filter(e => e.type === 'MOD');
|
|
180
|
+
function maxModuleSize(graph, policy) {
|
|
175
181
|
const violations = [];
|
|
182
|
+
const steps = policy.moduleSize;
|
|
183
|
+
if (steps === null)
|
|
184
|
+
return violations;
|
|
185
|
+
const modules = graph.elements.filter(e => e.type === 'MOD');
|
|
176
186
|
for (const mod of modules) {
|
|
177
187
|
const allocatedIds = graph.traces.filter(t => t.target === mod.id && t.type === 'allocate').map(t => t.source);
|
|
178
188
|
const allocated = allocatedIds.map(id => graph.elements.find(e => e.id === id)).filter((e) => !!e);
|
|
179
189
|
const funcCount = allocated.length;
|
|
180
|
-
if (funcCount <=
|
|
190
|
+
if (funcCount <= steps.coupled)
|
|
181
191
|
continue;
|
|
182
192
|
// Count crossing flows: io paths from FUNCs in this module to FUNCs in other modules
|
|
183
193
|
const funcIds = new Set(allocatedIds);
|
|
@@ -188,27 +198,27 @@ function maxModuleSize(graph) {
|
|
|
188
198
|
const tgtIn = funcIds.has(t.target);
|
|
189
199
|
return (srcIn && !tgtIn) || (!srcIn && tgtIn);
|
|
190
200
|
}).length;
|
|
191
|
-
if (funcCount >
|
|
201
|
+
if (funcCount > steps.large && crossings === 0) {
|
|
192
202
|
violations.push({
|
|
193
203
|
rule_id: 'R-04',
|
|
194
204
|
severity: 'info',
|
|
195
205
|
element_id: mod.id,
|
|
196
206
|
message: `${mod.id} has ${funcCount} functions but 0 crossings (cohesive, just large)`,
|
|
197
|
-
fix_hint:
|
|
207
|
+
fix_hint: `Size alone is not the finding: > ${steps.large} functions without crossing flows is cohesive. Split only if crossings appear`,
|
|
198
208
|
context: { element_type: mod.type, element_name: mod.name, candidate_targets: toCandidates(allocated) },
|
|
199
209
|
});
|
|
200
210
|
}
|
|
201
|
-
else if (funcCount >
|
|
211
|
+
else if (funcCount > steps.large && crossings > 0) {
|
|
202
212
|
violations.push({
|
|
203
213
|
rule_id: 'R-04',
|
|
204
214
|
severity: 'warning',
|
|
205
215
|
element_id: mod.id,
|
|
206
216
|
message: `${mod.id} has ${funcCount} functions and ${crossings} crossing flows (split recommended)`,
|
|
207
|
-
fix_hint:
|
|
217
|
+
fix_hint: `Split module into smaller units to reduce coupling (> ${steps.large} functions AND crossing flows)`,
|
|
208
218
|
context: { element_type: mod.type, element_name: mod.name, candidate_targets: toCandidates(allocated) },
|
|
209
219
|
});
|
|
210
220
|
}
|
|
211
|
-
else if (funcCount >
|
|
221
|
+
else if (funcCount > steps.coupled && crossings > steps.crossings) {
|
|
212
222
|
violations.push({
|
|
213
223
|
rule_id: 'R-04',
|
|
214
224
|
severity: 'warning',
|
|
@@ -439,7 +449,7 @@ function decompositionBreadth(graph) {
|
|
|
439
449
|
const byId = new Map(graph.elements.map(e => [e.id, e]));
|
|
440
450
|
const counts = new Map();
|
|
441
451
|
const bump = (parentId, kind) => {
|
|
442
|
-
const key = `${parentId}
|
|
452
|
+
const key = `${parentId}\u0000${kind}`;
|
|
443
453
|
const entry = counts.get(key);
|
|
444
454
|
if (entry)
|
|
445
455
|
entry.n++;
|
|
@@ -621,11 +631,11 @@ function validTracePattern(graph) {
|
|
|
621
631
|
}
|
|
622
632
|
// ---------------------------------------------------------------------------
|
|
623
633
|
// R-19: Runnable TEST binding (CR-GC-205 Item 4) — a TEST that is not explicitly
|
|
624
|
-
// concept-only (attributes.concept === true) should carry a valid
|
|
634
|
+
// concept-only (attributes.concept === true) should carry a valid testRefs runnable
|
|
625
635
|
// binding so the deduced selective test set is trustworthy. WARNING (a completeness
|
|
626
636
|
// signal like R-05, not a hard gate): a freshly-spec'd TEST is legitimately concept-
|
|
627
637
|
// level until implemented, and the no-phantom-file guarantee is enforced separately
|
|
628
|
-
// by the consumer's export materialization (every
|
|
638
|
+
// by the consumer's export materialization (every testRefs entry file is scaffolded). File
|
|
629
639
|
// EXISTENCE is out of scope here (rules are pure, no I/O); this guards presence/shape
|
|
630
640
|
// only and surfaces an unbound runnable TEST in rules_evaluate / readiness.
|
|
631
641
|
// ---------------------------------------------------------------------------
|
|
@@ -633,17 +643,71 @@ function testMustHaveRunnableBinding(graph) {
|
|
|
633
643
|
return graph.elements
|
|
634
644
|
.filter(e => e.type === 'TEST')
|
|
635
645
|
.filter(e => e.attributes?.concept !== true) // concept-only TESTs are exempt
|
|
636
|
-
|
|
646
|
+
// CR-SM-231: `testRefs` (Array, min 1) statt `testRef` (Objekt). Semantik unveraendert —
|
|
647
|
+
// Praesenz und Form, keine Datei-Existenz; die pruefst RC-02.
|
|
648
|
+
.filter(e => !TestRefsSchema.safeParse(e.attributes?.testRefs).success)
|
|
637
649
|
.map(test => ({
|
|
638
650
|
rule_id: 'R-19',
|
|
639
651
|
severity: 'warning',
|
|
640
652
|
element_id: test.id,
|
|
641
|
-
message: `${test.id} is a runnable TEST without a valid
|
|
642
|
-
fix_hint: 'Add attributes.
|
|
653
|
+
message: `${test.id} is a runnable TEST without a valid testRefs binding`,
|
|
654
|
+
fix_hint: 'Add attributes.testRefs [{file, case?, tool, level?}, …] with at least one entry, or set attributes.concept:true if it has no run artifact yet',
|
|
643
655
|
context: { element_type: test.type, element_name: test.name },
|
|
644
656
|
}));
|
|
645
657
|
}
|
|
646
658
|
// ---------------------------------------------------------------------------
|
|
659
|
+
// R-29: Testdatei-Exklusivitaet (CR-SM-231)
|
|
660
|
+
//
|
|
661
|
+
// Jede Testdatei erscheint in hoechstens einem `testRefs`. Das ist die Haelfte, die 1:n
|
|
662
|
+
// **erzwingt** statt es nur zu erlauben — ohne sie driftet das Attribut zurueck nach n:m,
|
|
663
|
+
// und genau das war der belegte Ist-Zustand: dieselbe Spec-Datei stand im `testRef` zweier
|
|
664
|
+
// TEST-Knoten. Folge: ein roter Lauf ist keiner Abnahme mehr eindeutig zuordenbar, und der
|
|
665
|
+
// TRR-Gate zaehlt dieselbe Evidenz doppelt.
|
|
666
|
+
//
|
|
667
|
+
// `error`, nicht `warning` (Entscheid 2026-08-13): eine doppelt beanspruchte Datei macht
|
|
668
|
+
// Gate-Zahlen nachweislich falsch. Das ist eine Fehlmessung, kein Vollstaendigkeits-Signal —
|
|
669
|
+
// und damit eine andere Klasse als R-19/R-20, die beide `warning` sind.
|
|
670
|
+
//
|
|
671
|
+
// Rein graph-strukturell, kein I/O: die Datei muss nicht existieren, um doppelt beansprucht
|
|
672
|
+
// zu sein.
|
|
673
|
+
// ---------------------------------------------------------------------------
|
|
674
|
+
function testFileExclusivity(graph) {
|
|
675
|
+
const claimedBy = new Map();
|
|
676
|
+
for (const el of graph.elements) {
|
|
677
|
+
if (el.type !== 'TEST')
|
|
678
|
+
continue;
|
|
679
|
+
const parsed = TestRefsSchema.safeParse(el.attributes?.testRefs);
|
|
680
|
+
if (!parsed.success)
|
|
681
|
+
continue; // keine/ungueltige Bindung → R-19-Gebiet
|
|
682
|
+
// Innerhalb EINES Knotens ist dieselbe Datei zweimal kein Konflikt, sondern eine
|
|
683
|
+
// Redundanz — sie wuerde sonst als Selbstkollision gemeldet.
|
|
684
|
+
for (const file of new Set(parsed.data.map(r => r.file))) {
|
|
685
|
+
const owners = claimedBy.get(file) ?? [];
|
|
686
|
+
owners.push(el.id);
|
|
687
|
+
claimedBy.set(file, owners);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const violations = [];
|
|
691
|
+
for (const [file, owners] of claimedBy) {
|
|
692
|
+
if (owners.length < 2)
|
|
693
|
+
continue;
|
|
694
|
+
const sorted = [...owners].sort();
|
|
695
|
+
// Einmal je beanspruchendem Knoten: jeder von ihnen muss handeln, und eine Meldung an
|
|
696
|
+
// nur einem waere fuer die anderen unsichtbar.
|
|
697
|
+
for (const owner of sorted) {
|
|
698
|
+
violations.push({
|
|
699
|
+
rule_id: 'R-29',
|
|
700
|
+
severity: 'error',
|
|
701
|
+
element_id: owner,
|
|
702
|
+
message: `${owner} claims test file '${file}', which is also claimed by ${sorted.filter(o => o !== owner).join(', ')}`,
|
|
703
|
+
fix_hint: 'A test file belongs to at most one TEST. Split the file, or drop the entry from all but the one acceptance it really evidences',
|
|
704
|
+
context: { element_type: 'TEST', element_name: graph.elements.find(e => e.id === owner)?.name },
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return violations;
|
|
709
|
+
}
|
|
710
|
+
// ---------------------------------------------------------------------------
|
|
647
711
|
// R-20: FUNC realRef binding (CR-GC-205 Item 5, extended by CR-210, unified CR-228)
|
|
648
712
|
// — a FUNC that is not explicitly concept-only (attributes.concept === true) or
|
|
649
713
|
// externally realized (attributes.external === true) counts as BOUND when it EITHER
|
|
@@ -876,7 +940,7 @@ function modMustHaveAllocatedFunc(graph) {
|
|
|
876
940
|
// so its Zod definition is machine-resolvable (RC-03 then checks it resolves, RC-04
|
|
877
941
|
// that it is parsed at the interface). WARNING, not error: currently-unbound SCHEMAs
|
|
878
942
|
// on the reference model must not turn readiness red before any binding exists — the
|
|
879
|
-
// presence signal mirrors R-20 (FUNC realRef) / R-19 (
|
|
943
|
+
// presence signal mirrors R-20 (FUNC realRef) / R-19 (testRefs). Symbol RESOLUTION is
|
|
880
944
|
// out of scope here (pure, no I/O — that is RC-03's job).
|
|
881
945
|
// ---------------------------------------------------------------------------
|
|
882
946
|
function schemaMustHaveSchemaRef(graph) {
|
|
@@ -953,35 +1017,36 @@ function ebenenPraesenz(graph) {
|
|
|
953
1017
|
}];
|
|
954
1018
|
}
|
|
955
1019
|
export const V3_RULES = [
|
|
956
|
-
{ id: 'R-01', name: 'REQ must have verification', severity: 'error', evaluate: reqMustHaveVerification },
|
|
957
|
-
{ id: 'R-02', name: 'FUNC must satisfy REQ', severity: 'warning', evaluate: funcMustSatisfyReq },
|
|
958
|
-
{ id: 'R-03', name: 'ASIL isolation', severity: 'error', evaluate: asilIsolation },
|
|
959
|
-
{ id: 'R-04', name: '
|
|
960
|
-
{ id: 'R-05', name: 'TEST must verify REQ', severity: 'warning', evaluate: testMustVerifyReq },
|
|
961
|
-
{ id: 'R-14', name: 'UC must have compose', severity: 'warning', evaluate: ucMustHaveCompose },
|
|
962
|
-
{ id: 'R-15', name: 'FCHAIN must have compose', severity: 'warning', evaluate: fchainMustHaveCompose },
|
|
963
|
-
{ id: 'R-16', name: 'ACTOR must have io', severity: 'warning', evaluate: actorMustHaveTrace },
|
|
964
|
-
{ id: 'R-17', name: 'SYS must have compose', severity: 'warning', evaluate: sysMustHaveCompose },
|
|
965
|
-
{ id: 'R-08', name: 'Trace consistency', severity: 'error', evaluate: traceConsistency },
|
|
966
|
-
{ id: 'R-10', name: 'FLOW completeness', severity: 'warning', evaluate: flowCompleteness },
|
|
967
|
-
{ id: 'R-12', name: 'No circular dependencies', severity: 'warning', evaluate: noDirectCircular },
|
|
968
|
-
{ id: 'R-18', name: 'Valid trace pattern', severity: 'error', evaluate: validTracePattern },
|
|
969
|
-
{ id: 'R-19', name: 'Runnable TEST binding', severity: 'warning', evaluate: testMustHaveRunnableBinding },
|
|
970
|
-
{ id: 'R-
|
|
971
|
-
{ id: 'R-
|
|
972
|
-
{ id: 'R-
|
|
973
|
-
{ id: 'R-
|
|
974
|
-
{ id: 'R-
|
|
975
|
-
{ id: 'R-
|
|
976
|
-
{ id: '
|
|
977
|
-
{ id: 'RD-
|
|
978
|
-
{ id: 'RD-
|
|
979
|
-
{ id: 'RD-
|
|
980
|
-
{ id: '
|
|
981
|
-
{ id: 'MS-
|
|
982
|
-
{ id: '
|
|
1020
|
+
{ id: 'R-01', name: 'REQ must have verification', severity: 'error', evaluate: reqMustHaveVerification, domain: ['REQ'] },
|
|
1021
|
+
{ id: 'R-02', name: 'FUNC must satisfy REQ', severity: 'warning', evaluate: funcMustSatisfyReq, domain: ['FUNC'] },
|
|
1022
|
+
{ id: 'R-03', name: 'ASIL isolation', severity: 'error', evaluate: asilIsolation, domain: ['FUNC'] },
|
|
1023
|
+
{ id: 'R-04', name: 'Module size relative to crossing flows', severity: 'warning', evaluate: maxModuleSize, domain: ['MOD'] },
|
|
1024
|
+
{ id: 'R-05', name: 'TEST must verify REQ', severity: 'warning', evaluate: testMustVerifyReq, domain: ['TEST'] },
|
|
1025
|
+
{ id: 'R-14', name: 'UC must have compose', severity: 'warning', evaluate: ucMustHaveCompose, domain: ['UC'] },
|
|
1026
|
+
{ id: 'R-15', name: 'FCHAIN must have compose', severity: 'warning', evaluate: fchainMustHaveCompose, domain: ['FCHAIN'] },
|
|
1027
|
+
{ id: 'R-16', name: 'ACTOR must have io', severity: 'warning', evaluate: actorMustHaveTrace, domain: ['ACTOR'] },
|
|
1028
|
+
{ id: 'R-17', name: 'SYS must have compose', severity: 'warning', evaluate: sysMustHaveCompose, domain: ['SYS'] },
|
|
1029
|
+
{ id: 'R-08', name: 'Trace consistency', severity: 'error', evaluate: traceConsistency, domain: ['all'] },
|
|
1030
|
+
{ id: 'R-10', name: 'FLOW completeness', severity: 'warning', evaluate: flowCompleteness, domain: ['FUNC'] },
|
|
1031
|
+
{ id: 'R-12', name: 'No circular dependencies', severity: 'warning', evaluate: noDirectCircular, domain: ['FUNC'] },
|
|
1032
|
+
{ id: 'R-18', name: 'Valid trace pattern', severity: 'error', evaluate: validTracePattern, domain: ['all'] },
|
|
1033
|
+
{ id: 'R-19', name: 'Runnable TEST binding', severity: 'warning', evaluate: testMustHaveRunnableBinding, domain: ['TEST'] },
|
|
1034
|
+
{ id: 'R-29', name: 'Test file exclusivity', severity: 'error', evaluate: testFileExclusivity, domain: ['TEST'] },
|
|
1035
|
+
{ id: 'R-20', name: 'FUNC realRef binding', severity: 'warning', evaluate: funcMustHaveCodeBinding, domain: ['FUNC'] },
|
|
1036
|
+
{ id: 'R-21', name: 'FUNC↔FUNC connection needs integration test', severity: 'warning', evaluate: fchainMustHaveIntegrationTest, domain: ['FCHAIN'] },
|
|
1037
|
+
{ id: 'R-22', name: 'FUNC must be allocated to MOD', severity: 'warning', evaluate: funcMustBeAllocated, domain: ['FUNC'] },
|
|
1038
|
+
{ id: 'R-23', name: 'MOD must have allocated FUNC', severity: 'warning', evaluate: modMustHaveAllocatedFunc, domain: ['MOD'] },
|
|
1039
|
+
{ id: 'R-26', name: 'SCHEMA must have realRef', severity: 'warning', evaluate: schemaMustHaveSchemaRef, domain: ['SCHEMA'] },
|
|
1040
|
+
{ id: 'R-27', name: 'Physical MOD must have realRef', severity: 'warning', evaluate: physicalModMustHaveRealRef, domain: ['MOD'] },
|
|
1041
|
+
{ id: 'RD-01', name: 'Unresolved requirement', severity: 'warning', evaluate: unresolvedRequirement, domain: ['REQ'] },
|
|
1042
|
+
{ id: 'RD-02', name: 'Decomposition consistency', severity: 'warning', evaluate: decompositionConsistency, domain: ['REQ'] },
|
|
1043
|
+
{ id: 'RD-03', name: 'No premature decomposition', severity: 'info', evaluate: noPrematureDecomposition, domain: ['REQ'] },
|
|
1044
|
+
{ id: 'RD-04', name: 'Decomposition breadth', severity: 'warning', evaluate: decompositionBreadth, domain: ['FUNC', 'MOD', 'SYS'] },
|
|
1045
|
+
{ id: 'MS-01', name: 'Milestone empty scope', severity: 'warning', evaluate: msEmptyScope, domain: ['MS'] },
|
|
1046
|
+
{ id: 'MS-02', name: 'Milestone dangling dependency', severity: 'error', evaluate: msDanglingDependency, domain: ['MS'] },
|
|
1047
|
+
{ id: 'R-28', name: 'Ebenen-Präsenz (FLOW+SCHEMA when funcCount>1)', severity: 'warning', evaluate: ebenenPraesenz, domain: ['SYS'] },
|
|
983
1048
|
];
|
|
984
|
-
/** Run all rules against a graph */
|
|
985
|
-
export function evaluateRules(graph) {
|
|
986
|
-
return V3_RULES.flatMap(rule => rule.evaluate(graph));
|
|
1049
|
+
/** Run all rules against a graph. CR-SM-236: `policy` ist Pflicht — wie bei `evaluateAllRules`. */
|
|
1050
|
+
export function evaluateRules(graph, policy) {
|
|
1051
|
+
return V3_RULES.flatMap(rule => rule.evaluate(graph, policy));
|
|
987
1052
|
}
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { OntologyGraph } from './ontology.js';
|
|
16
16
|
import type { RuleDefinition, RuleViolation } from './rules.js';
|
|
17
|
+
import type { MetricPolicy } from './policy.js';
|
|
17
18
|
export declare function sc02IsReferenced(graph: OntologyGraph): RuleViolation[];
|
|
18
19
|
export declare function sc04FlowHasSchema(graph: OntologyGraph): RuleViolation[];
|
|
19
20
|
export declare const SC_RULES: RuleDefinition[];
|
|
20
|
-
export declare function evaluateSCRules(graph: OntologyGraph): RuleViolation[];
|
|
21
|
+
export declare function evaluateSCRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|
|
@@ -49,9 +49,11 @@ export function sc04FlowHasSchema(graph) {
|
|
|
49
49
|
// Aggregated array & convenience runner
|
|
50
50
|
// ---------------------------------------------------------------------------
|
|
51
51
|
export const SC_RULES = [
|
|
52
|
-
{ id: 'SC-02', name: 'Schema referenced by FLOW', severity: 'warning', evaluate: sc02IsReferenced },
|
|
53
|
-
{ id: 'SC-04', name: 'FLOW has SCHEMA binding', severity: 'warning', evaluate: sc04FlowHasSchema },
|
|
52
|
+
{ id: 'SC-02', name: 'Schema referenced by FLOW', severity: 'warning', evaluate: sc02IsReferenced, domain: ['SCHEMA'] },
|
|
53
|
+
{ id: 'SC-04', name: 'FLOW has SCHEMA binding', severity: 'warning', evaluate: sc04FlowHasSchema, domain: ['SCHEMA'] },
|
|
54
54
|
];
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
// CR-SM-236: `policy` wird durchgereicht, auch wo diese Familie heute keine Schwelle hat —
|
|
56
|
+
// ein Sonderweg je Familie waere genau der zweite Pfad, den der Regelsatz verbietet.
|
|
57
|
+
export function evaluateSCRules(graph, policy) {
|
|
58
|
+
return SC_RULES.flatMap(rule => rule.evaluate(graph, policy));
|
|
57
59
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
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 uc01HasRequirements(graph: OntologyGraph): RuleViolation[];
|
|
7
8
|
export declare function uc02HasActor(graph: OntologyGraph): RuleViolation[];
|
|
8
9
|
export declare function uc03HasScenario(graph: OntologyGraph): RuleViolation[];
|
|
@@ -10,4 +11,4 @@ export declare function uc04GoalDefined(graph: OntologyGraph): RuleViolation[];
|
|
|
10
11
|
export declare function uc05HasPostcondition(graph: OntologyGraph): RuleViolation[];
|
|
11
12
|
export declare function uc06HasPrecondition(graph: OntologyGraph): RuleViolation[];
|
|
12
13
|
export declare const UC_RULES: RuleDefinition[];
|
|
13
|
-
export declare function evaluateUCRules(graph: OntologyGraph): RuleViolation[];
|
|
14
|
+
export declare function evaluateUCRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];
|