@sigloch/se-engine 1.5.0 → 1.6.1
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/metrics.d.ts +1 -1
- package/dist/metrics.js +6 -1
- package/dist/rule-apply.js +12 -6
- package/dist/rule-classify.d.ts +27 -0
- package/dist/rule-classify.js +42 -1
- package/dist/steer.d.ts +28 -0
- package/dist/steer.js +36 -19
- package/dist/suggest.js +8 -3
- package/package.json +1 -1
package/dist/metrics.d.ts
CHANGED
|
@@ -49,6 +49,6 @@ export { projectLayer, weightNodes, ARCH_TYPES, type MetricLayer } from './layer
|
|
|
49
49
|
export { CLASS_MAP, classOf, classifyAll, classificationStats, type RuleClass, type Classification, type ClassifiedRule, type ClassificationStats, } from './rule-classify.js';
|
|
50
50
|
export { applyRule, markEmptyDelta, type ApplyResult, type DeltaMark } from './rule-apply.js';
|
|
51
51
|
export { suggestEdits, type Suggestion, type SuggestOptions } from './suggest.js';
|
|
52
|
-
export { steerScore, beatsBySteer, STEER_RULES, EPS_AUGMENT, type SteerScore, type SteerCandidate } from './steer.js';
|
|
52
|
+
export { steerScore, steerTerms, beatsBySteer, STEER_RULES, EPS_AUGMENT, type SteerScore, type SteerTerm, type SteerCandidate, } from './steer.js';
|
|
53
53
|
export { fixFor, mentionedElements, FIX_TEMPLATES, mergeCandidates, applyMergeEdit, contractSimilarity, MERGE_OPERATOR_ID, MERGE_SIMILARITY_THRESHOLD, type SuggestedEdit, } from './fix-templates.js';
|
|
54
54
|
export { buildAdjacency, betweenness, maxBetweenness, detectCommunities, modularityOf, modularityQ, redundancyDensity, intraEdgeFraction, components, componentSizes, sourceSinkPaths, type Adjacency, } from './topology.js';
|
package/dist/metrics.js
CHANGED
|
@@ -94,6 +94,11 @@ export { CLASS_MAP, classOf, classifyAll, classificationStats, } from './rule-cl
|
|
|
94
94
|
export { applyRule, markEmptyDelta } from './rule-apply.js';
|
|
95
95
|
export { suggestEdits } from './suggest.js';
|
|
96
96
|
// CR-SM-292: der Ranking-Score. `targetFor` ist mit dem ℝ⁶-Ranking ersatzlos entfallen.
|
|
97
|
-
|
|
97
|
+
// CR-SM-340: `steerTerms`/`SteerTerm` sind hier nachgetragen. CR-SM-337 hat sie gebaut, damit
|
|
98
|
+
// der Host den Steuerungsraum EXPORTIEREN kann, statt die Normierung ein zweites Mal zu
|
|
99
|
+
// schreiben — und genau diese Zeile hat sie nicht durchgereicht. Die Funktion war da, die Tuer
|
|
100
|
+
// nicht; `package.json` kennt nur `"."`, ein Tiefimport ist also versperrt. Gemessen an
|
|
101
|
+
// graphcode: `import { steerTerms } from '@sigloch/se-engine'` warf SyntaxError.
|
|
102
|
+
export { steerScore, steerTerms, beatsBySteer, STEER_RULES, EPS_AUGMENT, } from './steer.js';
|
|
98
103
|
export { fixFor, mentionedElements, FIX_TEMPLATES, mergeCandidates, applyMergeEdit, contractSimilarity, MERGE_OPERATOR_ID, MERGE_SIMILARITY_THRESHOLD, } from './fix-templates.js';
|
|
99
104
|
export { buildAdjacency, betweenness, maxBetweenness, detectCommunities, modularityOf, modularityQ, redundancyDensity, intraEdgeFraction, components, componentSizes, sourceSinkPaths, } from './topology.js';
|
package/dist/rule-apply.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* Edit; Vorschläge laufen durchs Gate (nie auto-apply).
|
|
19
19
|
*/
|
|
20
20
|
import { evaluateAllRules, isValidTrace } from '@sigloch/contracts/se';
|
|
21
|
-
import { classOf, MT_IRRELEVANT_POLICY } from './rule-classify.js';
|
|
21
|
+
import { classOf, classOfViolation, MT_IRRELEVANT_POLICY } from './rule-classify.js';
|
|
22
22
|
/** Deterministic timestamp for synthesized traces (no Date.now — keeps metrics stable). */
|
|
23
23
|
const APPLY_TS = '2026-07-26T00:00:00.000Z';
|
|
24
24
|
/**
|
|
@@ -52,19 +52,25 @@ function addTrace(graph, source, target, type) {
|
|
|
52
52
|
* @returns graph' + whether an edit was applied. Deterministic.
|
|
53
53
|
*/
|
|
54
54
|
export function applyRule(rule, graph, knownViolations) {
|
|
55
|
-
const cls = classOf(rule.id);
|
|
56
55
|
const allViolations = knownViolations ?? evaluateAllRules(graph, MT_IRRELEVANT_POLICY);
|
|
57
|
-
const
|
|
58
|
-
|
|
56
|
+
const typeById = new Map(graph.elements.map((e) => [e.id, e.type]));
|
|
57
|
+
const forRule = allViolations.filter((v) => v.rule_id === rule.id);
|
|
58
|
+
if (forRule.length === 0) {
|
|
59
59
|
return { graph, applied: false, reason: 'rule does not fire on this graph (empty Δm)' };
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
// CR-SM-334: die Klasse haengt bei R-21 am Ankerknoten des BEFUNDS, nicht nur an der Regel —
|
|
62
|
+
// ein Befund am Sender-FUNC (Zweig 3, keine gemeinsame Kette) ist kein Operator, auch wenn
|
|
63
|
+
// die Regel als Ganzes einer ist. Sonst schlaegt der Optimizer einen Test vor, wo die
|
|
64
|
+
// Modellierung fehlt.
|
|
65
|
+
const violations = forRule.filter((v) => classOfViolation(rule.id, typeById.get(v.element_id)).class === 'Operator');
|
|
66
|
+
if (violations.length === 0) {
|
|
67
|
+
const cls = classOfViolation(rule.id, typeById.get(forRule[0].element_id));
|
|
62
68
|
return { graph, applied: false, reason: `class=${cls.class}: not a transforming operator` };
|
|
63
69
|
}
|
|
64
70
|
// Find a single additive edge that (a) is meta-model valid for the two
|
|
65
71
|
// elements' stored types (isValidTrace) and (b) links two currently-
|
|
66
72
|
// unconnected nodes, so it genuinely moves the topology.
|
|
67
|
-
|
|
73
|
+
// (`typeById` steht seit CR-SM-334 weiter oben — die Klassifikation je Befund braucht es.)
|
|
68
74
|
// CR-SM-266 B: die where-Patterns lesen die Kinds des Zielknotens mit. Ohne sie wuerde
|
|
69
75
|
// `isValidTrace` jede satisfy-Kante ablehnen und der Operator griffe stumm auf einen anderen
|
|
70
76
|
// Kantentyp aus — ein falscher Vorschlag statt keinem.
|
package/dist/rule-classify.d.ts
CHANGED
|
@@ -21,6 +21,33 @@ export interface Classification {
|
|
|
21
21
|
export declare const CLASS_MAP: Record<string, Classification>;
|
|
22
22
|
/** Classify a single rule id (falls back to ambiguous-unknown). */
|
|
23
23
|
export declare function classOf(ruleId: string): Classification;
|
|
24
|
+
/**
|
|
25
|
+
* CR-SM-334 (ITEM-2026-095) — die Klasse einer Regel, die MEHRERE Fragen stellt, haengt am
|
|
26
|
+
* ANKERKNOTEN des Befunds, nicht nur an der Regel-ID.
|
|
27
|
+
*
|
|
28
|
+
* Bisher einziger Fall: R-21 seit seiner scharfen Fassung (CR-SM-313). Die Regel hat drei
|
|
29
|
+
* Zweige, und ihre `domain` waechst genau deshalb auf ['FCHAIN','FUNC']:
|
|
30
|
+
* 1. ein Ende in GAR KEINER Kette -> still, das ist R-30s Aussage
|
|
31
|
+
* 2. gemeinsame Kette, aber keine geprueft -> Befund an der KETTE (FCHAIN)
|
|
32
|
+
* 3. beide in Ketten, aber KEINE gemeinsame -> Befund am SENDER (FUNC)
|
|
33
|
+
*
|
|
34
|
+
* Zweig 2 ist ein Operator: es fehlt ein Integrationstest, der Fix fuegt TEST + verify hinzu.
|
|
35
|
+
* Zweig 3 ist etwas anderes, und der Unterschied ist teuer. Dort fehlt kein Test, sondern die
|
|
36
|
+
* gemeinsame KETTE — zwei Funktionen reichen einander etwas, ohne dass das Modell sagt, in
|
|
37
|
+
* welchem Ablauf das passiert. Ein Operator, der hier einen Test vorschlaegt, erzeugt
|
|
38
|
+
* Testarbeit an einer Stelle, an der Modellierungsarbeit fehlt: der Test wuerde eine
|
|
39
|
+
* Uebergabe belegen, die im Modell gar nicht vorgesehen ist.
|
|
40
|
+
*
|
|
41
|
+
* ENTSCHEIDUNG ZUR KLASSE (Kriterium 3 des CR): Zweig 3 ist **Constraint, ambiguous**. Der
|
|
42
|
+
* Fix waere zwar additiv (compose-Kanten), aber WELCHE Kette die beiden teilen sollen —
|
|
43
|
+
* die des Senders verlaengern, die des Empfaengers, oder eine neue aufmachen — steht in
|
|
44
|
+
* keinem Feld; das ist Modellierungsabsicht. Ein Operator daraus waere geraten, nicht
|
|
45
|
+
* abgeleitet, und wuerde falsche compose-Kanten erzeugen. Praezedenz: IO-02 ("welcher
|
|
46
|
+
* Produzent welche Konsumenten behaelt, steht in keinem Feld") und die sechs RC-Regeln
|
|
47
|
+
* (CR-SM-305). `applyRule`/`suggestEdits` verwerfen Nicht-Operatoren — Zweig 3 bleibt damit
|
|
48
|
+
* Befund und Steuersignal, was er ist.
|
|
49
|
+
*/
|
|
50
|
+
export declare function classOfViolation(ruleId: string, elementType?: string): Classification;
|
|
24
51
|
export interface ClassifiedRule {
|
|
25
52
|
id: string;
|
|
26
53
|
name: string;
|
package/dist/rule-classify.js
CHANGED
|
@@ -62,7 +62,11 @@ export const CLASS_MAP = {
|
|
|
62
62
|
'R-15': { class: 'Operator', rationale: 'add compose trace FCHAIN→FUNC' },
|
|
63
63
|
'R-16': { class: 'Operator', rationale: 'add io trace ACTOR→UC/FLOW' },
|
|
64
64
|
'R-17': { class: 'Operator', rationale: 'add compose trace SYS→child' },
|
|
65
|
-
|
|
65
|
+
// CR-SM-334 (ITEM-2026-095, zugesagt in CR-SM-313): dieser Eintrag gilt fuer ZWEIG 2 —
|
|
66
|
+
// Befund an der KETTE, beide Enden teilen eine Kette, nur geprueft ist sie nicht. Zweig 3
|
|
67
|
+
// (Befund am SENDER-FUNC) verlangt einen anderen Fix und wird in `classOfViolation`
|
|
68
|
+
// unterschieden; die Klasse allein kann das nicht tragen, denn sie haengt am Ankerknoten.
|
|
69
|
+
'R-21': { class: 'Operator', rationale: 'chain has no integration TEST — add TEST + verify for the shared chain' },
|
|
66
70
|
'R-22': { class: 'Operator', rationale: 'add allocate trace FUNC→MOD' },
|
|
67
71
|
'R-23': { class: 'Operator', rationale: 'add allocate trace MOD←FUNC' },
|
|
68
72
|
'RD-01': { class: 'Operator', rationale: 'resolve REQ by adding satisfy/decompose trace' },
|
|
@@ -159,6 +163,43 @@ const UNKNOWN = { class: 'Constraint', rationale: 'unclassified — not in CLASS
|
|
|
159
163
|
export function classOf(ruleId) {
|
|
160
164
|
return CLASS_MAP[ruleId] ?? UNKNOWN;
|
|
161
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* CR-SM-334 (ITEM-2026-095) — die Klasse einer Regel, die MEHRERE Fragen stellt, haengt am
|
|
168
|
+
* ANKERKNOTEN des Befunds, nicht nur an der Regel-ID.
|
|
169
|
+
*
|
|
170
|
+
* Bisher einziger Fall: R-21 seit seiner scharfen Fassung (CR-SM-313). Die Regel hat drei
|
|
171
|
+
* Zweige, und ihre `domain` waechst genau deshalb auf ['FCHAIN','FUNC']:
|
|
172
|
+
* 1. ein Ende in GAR KEINER Kette -> still, das ist R-30s Aussage
|
|
173
|
+
* 2. gemeinsame Kette, aber keine geprueft -> Befund an der KETTE (FCHAIN)
|
|
174
|
+
* 3. beide in Ketten, aber KEINE gemeinsame -> Befund am SENDER (FUNC)
|
|
175
|
+
*
|
|
176
|
+
* Zweig 2 ist ein Operator: es fehlt ein Integrationstest, der Fix fuegt TEST + verify hinzu.
|
|
177
|
+
* Zweig 3 ist etwas anderes, und der Unterschied ist teuer. Dort fehlt kein Test, sondern die
|
|
178
|
+
* gemeinsame KETTE — zwei Funktionen reichen einander etwas, ohne dass das Modell sagt, in
|
|
179
|
+
* welchem Ablauf das passiert. Ein Operator, der hier einen Test vorschlaegt, erzeugt
|
|
180
|
+
* Testarbeit an einer Stelle, an der Modellierungsarbeit fehlt: der Test wuerde eine
|
|
181
|
+
* Uebergabe belegen, die im Modell gar nicht vorgesehen ist.
|
|
182
|
+
*
|
|
183
|
+
* ENTSCHEIDUNG ZUR KLASSE (Kriterium 3 des CR): Zweig 3 ist **Constraint, ambiguous**. Der
|
|
184
|
+
* Fix waere zwar additiv (compose-Kanten), aber WELCHE Kette die beiden teilen sollen —
|
|
185
|
+
* die des Senders verlaengern, die des Empfaengers, oder eine neue aufmachen — steht in
|
|
186
|
+
* keinem Feld; das ist Modellierungsabsicht. Ein Operator daraus waere geraten, nicht
|
|
187
|
+
* abgeleitet, und wuerde falsche compose-Kanten erzeugen. Praezedenz: IO-02 ("welcher
|
|
188
|
+
* Produzent welche Konsumenten behaelt, steht in keinem Feld") und die sechs RC-Regeln
|
|
189
|
+
* (CR-SM-305). `applyRule`/`suggestEdits` verwerfen Nicht-Operatoren — Zweig 3 bleibt damit
|
|
190
|
+
* Befund und Steuersignal, was er ist.
|
|
191
|
+
*/
|
|
192
|
+
export function classOfViolation(ruleId, elementType) {
|
|
193
|
+
if (ruleId === 'R-21' && elementType === 'FUNC') {
|
|
194
|
+
return {
|
|
195
|
+
class: 'Constraint',
|
|
196
|
+
rationale: 'handover without a shared chain — model the common FCHAIN; which chain the two '
|
|
197
|
+
+ 'functions should share is modelling intent, not derivable, so no operator',
|
|
198
|
+
ambiguous: true,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return classOf(ruleId);
|
|
202
|
+
}
|
|
162
203
|
/** Classify the entire live rule catalog (ALL_RULE_DEFS). */
|
|
163
204
|
export function classifyAll() {
|
|
164
205
|
return ALL_RULE_DEFS.map((r) => {
|
package/dist/steer.d.ts
CHANGED
|
@@ -80,6 +80,34 @@ export interface SteerScore {
|
|
|
80
80
|
/** Zahl der Blackboxes, die in die Rechnung eingegangen sind. */
|
|
81
81
|
measured: number;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* CR-SM-337 (ITEM-2026-059): ein TERM je gemessener Blackbox — die Zwischenrechnung, aus der
|
|
85
|
+
* `worst` und `mean` entstehen.
|
|
86
|
+
*
|
|
87
|
+
* Bis hierher gab `steerScore` nur das Ergebnis heraus. Wer die Terme brauchte — der Host, um
|
|
88
|
+
* den Steuerungsraum zu exportieren, das GVE-Dashboard, um ihn zu zeigen — musste sie selbst
|
|
89
|
+
* aus dem Regelstrom ableiten, also die Normierung ein zweites Mal schreiben. Eine zweite
|
|
90
|
+
* Rechnung ist eine zweite Wahrheit; hier ist sie vermeidbar, weil die Zwischenschritte schon
|
|
91
|
+
* existierten und nur nicht herausgereicht wurden.
|
|
92
|
+
*
|
|
93
|
+
* Die Form spiegelt `SteerTerm` in @sigloch/contracts (`se/readiness.ts`) — dort der Vertrag,
|
|
94
|
+
* hier die Rechnung.
|
|
95
|
+
*/
|
|
96
|
+
export interface SteerTerm {
|
|
97
|
+
ruleId: string;
|
|
98
|
+
elementId: string;
|
|
99
|
+
value: number;
|
|
100
|
+
threshold: number;
|
|
101
|
+
/** `max(0, (value − threshold) / threshold)`, dimensionslos. */
|
|
102
|
+
overshoot: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Die Terme des Steuerungsraums, in kanonischer Befund-Reihenfolge (CR-SM-240). Rein.
|
|
106
|
+
*
|
|
107
|
+
* DIE Quelle für alles Weitere: `steerScore` rechnet daraus, der Host exportiert sie
|
|
108
|
+
* unverändert. Es gibt genau eine Normierung und genau eine Regel-Liste.
|
|
109
|
+
*/
|
|
110
|
+
export declare function steerTerms(violations: readonly RuleViolation[]): SteerTerm[];
|
|
83
111
|
/** Der Chebyshev-Score eines Zustands, aus seinem Regelstrom. Rein. */
|
|
84
112
|
export declare function steerScore(violations: readonly RuleViolation[]): SteerScore;
|
|
85
113
|
/** Ein Kandidat, so weit der Ranker ihn kennen muss. */
|
package/dist/steer.js
CHANGED
|
@@ -37,39 +37,56 @@ const NEUTRAL = { worst: 0, worstAt: null, mean: 0, score: 0, measured: 0 };
|
|
|
37
37
|
* ist nicht „keine Überschreitung". Dieselbe Konvention wie `policy.X = null` und
|
|
38
38
|
* `moduleMetrics.instability = null`.
|
|
39
39
|
*/
|
|
40
|
-
function
|
|
40
|
+
function termOf(v) {
|
|
41
41
|
const value = v.context?.value;
|
|
42
42
|
const budget = v.context?.threshold;
|
|
43
43
|
if (typeof value !== 'number' || typeof budget !== 'number' || budget <= 0)
|
|
44
44
|
return null;
|
|
45
|
-
return
|
|
45
|
+
return {
|
|
46
|
+
ruleId: v.rule_id,
|
|
47
|
+
elementId: v.element_id,
|
|
48
|
+
value,
|
|
49
|
+
threshold: budget,
|
|
50
|
+
overshoot: Math.max(0, (value - budget) / budget),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Die Terme des Steuerungsraums, in kanonischer Befund-Reihenfolge (CR-SM-240). Rein.
|
|
55
|
+
*
|
|
56
|
+
* DIE Quelle für alles Weitere: `steerScore` rechnet daraus, der Host exportiert sie
|
|
57
|
+
* unverändert. Es gibt genau eine Normierung und genau eine Regel-Liste.
|
|
58
|
+
*/
|
|
59
|
+
export function steerTerms(violations) {
|
|
60
|
+
const rules = STEER_RULES;
|
|
61
|
+
const terms = [];
|
|
62
|
+
for (const v of violations) {
|
|
63
|
+
if (!rules.includes(v.rule_id))
|
|
64
|
+
continue;
|
|
65
|
+
const t = termOf(v);
|
|
66
|
+
if (t !== null)
|
|
67
|
+
terms.push(t);
|
|
68
|
+
}
|
|
69
|
+
return terms;
|
|
46
70
|
}
|
|
47
71
|
/** Der Chebyshev-Score eines Zustands, aus seinem Regelstrom. Rein. */
|
|
48
72
|
export function steerScore(violations) {
|
|
49
|
-
const
|
|
73
|
+
const terms = steerTerms(violations);
|
|
74
|
+
if (terms.length === 0)
|
|
75
|
+
return NEUTRAL;
|
|
50
76
|
let worst = 0;
|
|
51
77
|
let worstAt = null;
|
|
52
78
|
let sum = 0;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (!rules.includes(v.rule_id))
|
|
56
|
-
continue;
|
|
57
|
-
const d = overshootOf(v);
|
|
58
|
-
if (d === null)
|
|
59
|
-
continue;
|
|
60
|
-
measured += 1;
|
|
61
|
-
sum += d;
|
|
79
|
+
for (const t of terms) {
|
|
80
|
+
sum += t.overshoot;
|
|
62
81
|
// `>` statt `>=`: bei Gleichstand gewinnt der zuerst gesehene, und die Befund-Sequenz ist
|
|
63
82
|
// seit CR-SM-240 kanonisch — damit ist `worstAt` deterministisch.
|
|
64
|
-
if (
|
|
65
|
-
worst =
|
|
66
|
-
worstAt = { ruleId:
|
|
83
|
+
if (t.overshoot > worst) {
|
|
84
|
+
worst = t.overshoot;
|
|
85
|
+
worstAt = { ruleId: t.ruleId, elementId: t.elementId };
|
|
67
86
|
}
|
|
68
87
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const mean = sum / measured;
|
|
72
|
-
return { worst, worstAt, mean, score: worst + EPS_AUGMENT * mean, measured };
|
|
88
|
+
const mean = sum / terms.length;
|
|
89
|
+
return { worst, worstAt, mean, score: worst + EPS_AUGMENT * mean, measured: terms.length };
|
|
73
90
|
}
|
|
74
91
|
/**
|
|
75
92
|
* Vergleicht zwei Kandidaten. `< 0` heisst **a ist besser**; direkt sortierbar.
|
package/dist/suggest.js
CHANGED
|
@@ -19,7 +19,7 @@ import { evaluateAllRules } from '@sigloch/contracts/se';
|
|
|
19
19
|
import { metrics, toArray } from './metrics.js';
|
|
20
20
|
import { steerScore, beatsBySteer } from './steer.js';
|
|
21
21
|
import { applyRule } from './rule-apply.js';
|
|
22
|
-
import {
|
|
22
|
+
import { classOfViolation, MT_IRRELEVANT_POLICY } from './rule-classify.js';
|
|
23
23
|
import { fixFor, mergeCandidates, applyMergeEdit, MERGE_OPERATOR_ID } from './fix-templates.js';
|
|
24
24
|
/**
|
|
25
25
|
* Rankt die feuernden Operator-Regeln danach, wie weit ihr Sonden-Edit den **Chebyshev-Score**
|
|
@@ -43,9 +43,14 @@ export function suggestEdits(graph, opts = {}) {
|
|
|
43
43
|
for (const v of violations)
|
|
44
44
|
if (!firstByRule.has(v.rule_id))
|
|
45
45
|
firstByRule.set(v.rule_id, v);
|
|
46
|
+
// CR-SM-334: die Klasse haengt bei R-21 am Ankerknoten des Befunds. Ohne den Typ schlaegt
|
|
47
|
+
// der Vorschlag fuer Zweig 3 (Uebergabe ohne gemeinsame Kette) einen Integrationstest vor,
|
|
48
|
+
// wo die gemeinsame Kette fehlt — Testarbeit statt Modellierungsarbeit.
|
|
49
|
+
const typeOfElement = new Map(graph.elements.map((e) => [e.id, e.type]));
|
|
50
|
+
const classOfFinding = (ruleId, elementId) => classOfViolation(ruleId, typeOfElement.get(elementId));
|
|
46
51
|
const suggestions = [];
|
|
47
52
|
for (const [ruleId, v] of firstByRule) {
|
|
48
|
-
if (
|
|
53
|
+
if (classOfFinding(ruleId, v.element_id).class !== 'Operator')
|
|
49
54
|
continue;
|
|
50
55
|
const probe = applyRule({ id: ruleId }, graph, violations);
|
|
51
56
|
if (!probe.applied)
|
|
@@ -77,7 +82,7 @@ export function suggestEdits(graph, opts = {}) {
|
|
|
77
82
|
// ohnehin nicht anwendbar — vor diesem Block fiel der Fund deshalb ganz heraus, mitsamt
|
|
78
83
|
// dem vertragsbauenden Arm des Aktionsraums (CR-GC-430: COHESIVE 5 -> 2 Schritte).
|
|
79
84
|
for (const [ruleId, v] of firstByRule) {
|
|
80
|
-
if (
|
|
85
|
+
if (classOfFinding(ruleId, v.element_id).class === 'Operator')
|
|
81
86
|
continue;
|
|
82
87
|
const edit = fixFor(v, graph);
|
|
83
88
|
if (!edit || edit.op !== 'add-trace')
|