@sigloch/se-engine 1.4.1 → 1.5.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/fix-templates.d.ts +10 -2
- package/dist/fix-templates.js +38 -5
- package/dist/readiness-compute.d.ts +5 -5
- package/dist/readiness-compute.js +24 -14
- package/dist/rule-classify.js +13 -1
- package/dist/steer.d.ts +6 -5
- package/dist/steer.js +1 -1
- package/package.json +1 -1
package/dist/fix-templates.d.ts
CHANGED
|
@@ -118,8 +118,16 @@ export declare const MERGE_SIMILARITY_THRESHOLD = 0.85;
|
|
|
118
118
|
*/
|
|
119
119
|
export declare function contractSimilarity(g: OntologyGraph, a: string, b: string): number;
|
|
120
120
|
/**
|
|
121
|
-
* Konsolidierungs-Kandidaten: FLOW-Paare, die DENSELBEN Datenvertrag tragen
|
|
122
|
-
*
|
|
121
|
+
* Konsolidierungs-Kandidaten: FLOW-Paare, die DENSELBEN Datenvertrag tragen UND dieselbe
|
|
122
|
+
* Verbindung sind — gleiche Produzenten, gleiche Konsumenten (CR-GC-444, CR-SM-309).
|
|
123
|
+
*
|
|
124
|
+
* CR-SM-309: vorher genuegte der gleiche Vertrag. Seit CR-GC-510 ist „ein FLOW je
|
|
125
|
+
* Verbindung, n FLOW -> 1 SCHEMA" das Modell, und IO-02 blockt am Gate. Ein Merge zweier
|
|
126
|
+
* FLOWs mit verschiedenen Produzenten legte zwei Quellen in einen Fluss (IO-02); einer mit
|
|
127
|
+
* gleichem Produzenten, aber verschiedenen Konsumenten behauptete Verbindungen, die es nicht
|
|
128
|
+
* gibt. Gemessen an graphcode v261: alle 11 Vorschlaege der alten Fassung verletzten IO-02
|
|
129
|
+
* und wurden am Gate abgewiesen. Echt verschmelzbar sind nur DUPLIKATE — derselbe Vertrag
|
|
130
|
+
* auf derselben Verbindung, zweimal modelliert.
|
|
123
131
|
*
|
|
124
132
|
* „Derselbe Vertrag" = `contractSimilarity` (identischer SCHEMA-Knoten oder
|
|
125
133
|
* ND-02-Duplikat) — EINE Definition, keine neue Zahl. Ein FLOW ohne oder mit
|
package/dist/fix-templates.js
CHANGED
|
@@ -439,9 +439,35 @@ function coupledMerges(g, drop, keep) {
|
|
|
439
439
|
function ioDegree(g, id) {
|
|
440
440
|
return g.traces.filter((t) => t.type === 'io' && (t.source === id || t.target === id)).length;
|
|
441
441
|
}
|
|
442
|
+
/** Produzenten- und Konsumentenmenge eines FLOW als Signatur (FUNC/ACTOR-Enden, sortiert). */
|
|
443
|
+
function endpointSignature(g, flowId) {
|
|
444
|
+
const isEnd = (id) => {
|
|
445
|
+
const t = byId(g, id)?.type;
|
|
446
|
+
return t === 'FUNC' || t === 'ACTOR';
|
|
447
|
+
};
|
|
448
|
+
const producers = new Set();
|
|
449
|
+
const consumers = new Set();
|
|
450
|
+
for (const t of g.traces) {
|
|
451
|
+
if (t.type !== 'io')
|
|
452
|
+
continue;
|
|
453
|
+
if (t.target === flowId && isEnd(t.source))
|
|
454
|
+
producers.add(t.source);
|
|
455
|
+
if (t.source === flowId && isEnd(t.target))
|
|
456
|
+
consumers.add(t.target);
|
|
457
|
+
}
|
|
458
|
+
return `${[...producers].sort().join(',')}|${[...consumers].sort().join(',')}`;
|
|
459
|
+
}
|
|
442
460
|
/**
|
|
443
|
-
* Konsolidierungs-Kandidaten: FLOW-Paare, die DENSELBEN Datenvertrag tragen
|
|
444
|
-
*
|
|
461
|
+
* Konsolidierungs-Kandidaten: FLOW-Paare, die DENSELBEN Datenvertrag tragen UND dieselbe
|
|
462
|
+
* Verbindung sind — gleiche Produzenten, gleiche Konsumenten (CR-GC-444, CR-SM-309).
|
|
463
|
+
*
|
|
464
|
+
* CR-SM-309: vorher genuegte der gleiche Vertrag. Seit CR-GC-510 ist „ein FLOW je
|
|
465
|
+
* Verbindung, n FLOW -> 1 SCHEMA" das Modell, und IO-02 blockt am Gate. Ein Merge zweier
|
|
466
|
+
* FLOWs mit verschiedenen Produzenten legte zwei Quellen in einen Fluss (IO-02); einer mit
|
|
467
|
+
* gleichem Produzenten, aber verschiedenen Konsumenten behauptete Verbindungen, die es nicht
|
|
468
|
+
* gibt. Gemessen an graphcode v261: alle 11 Vorschlaege der alten Fassung verletzten IO-02
|
|
469
|
+
* und wurden am Gate abgewiesen. Echt verschmelzbar sind nur DUPLIKATE — derselbe Vertrag
|
|
470
|
+
* auf derselben Verbindung, zweimal modelliert.
|
|
445
471
|
*
|
|
446
472
|
* „Derselbe Vertrag" = `contractSimilarity` (identischer SCHEMA-Knoten oder
|
|
447
473
|
* ND-02-Duplikat) — EINE Definition, keine neue Zahl. Ein FLOW ohne oder mit
|
|
@@ -492,11 +518,18 @@ export function mergeCandidates(g) {
|
|
|
492
518
|
}
|
|
493
519
|
const edits = [];
|
|
494
520
|
for (const key of [...grouped.keys()].sort()) {
|
|
495
|
-
|
|
521
|
+
// CR-SM-309: innerhalb des Vertrags nur FLOWs derselben Verbindung (Endpunkt-Signatur).
|
|
522
|
+
const byEnds = new Map();
|
|
523
|
+
for (const f of grouped.get(key)) {
|
|
524
|
+
const sig = endpointSignature(g, f.id);
|
|
525
|
+
byEnds.set(sig, [...(byEnds.get(sig) ?? []), f]);
|
|
526
|
+
}
|
|
527
|
+
const duplicates = [...byEnds.keys()].sort().map((sig) => byEnds.get(sig)).find((m) => m.length >= 2);
|
|
528
|
+
if (!duplicates)
|
|
529
|
+
continue;
|
|
530
|
+
const members = duplicates
|
|
496
531
|
.slice()
|
|
497
532
|
.sort((a, b) => ioDegree(g, b.id) - ioDegree(g, a.id) || a.id.localeCompare(b.id));
|
|
498
|
-
if (members.length < 2)
|
|
499
|
-
continue;
|
|
500
533
|
const [keep, drop] = members;
|
|
501
534
|
const merges = coupledMerges(g, drop, keep);
|
|
502
535
|
if (merges === null)
|
|
@@ -19,12 +19,12 @@ import { type ReadinessDimensionType, type ReadinessReportType } from '@sigloch/
|
|
|
19
19
|
* CR-SM-233: `policy` reicht bis zu den Regeln durch und hat keinen Default — sonst urteilte
|
|
20
20
|
* die Readiness mit einer anderen Schwelle als die, die der Host anzeigt.
|
|
21
21
|
*
|
|
22
|
-
* CR-SM-
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* CR-SM-310: keine Schwelle mehr. CR-SM-235 hatte `readyThreshold` hereingereicht, damit es nur
|
|
23
|
+
* EINEN Wert fuer „ist diese Dimension zu schwach?" gibt — das Urteil stand danach trotzdem
|
|
24
|
+
* zweimal, hier als `ready` und beim Konsumenten (graphcode generate.ts). Messen und Urteilen
|
|
25
|
+
* sind getrennt: diese Funktion misst, der Konsument urteilt mit seiner Config.
|
|
26
26
|
*/
|
|
27
|
-
export declare function computeReadiness(graph: OntologyGraph, policy: MetricPolicy
|
|
27
|
+
export declare function computeReadiness(graph: OntologyGraph, policy: MetricPolicy): ReadinessReportType;
|
|
28
28
|
/**
|
|
29
29
|
* CR-146 / CR-SM-235: Anzahl anwendbarer Pruefungen je Dimension.
|
|
30
30
|
*
|
|
@@ -14,12 +14,12 @@ import { ReadinessDimension, RULE_TO_DIMENSION, } from '@sigloch/contracts/se';
|
|
|
14
14
|
* CR-SM-233: `policy` reicht bis zu den Regeln durch und hat keinen Default — sonst urteilte
|
|
15
15
|
* die Readiness mit einer anderen Schwelle als die, die der Host anzeigt.
|
|
16
16
|
*
|
|
17
|
-
* CR-SM-
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* CR-SM-310: keine Schwelle mehr. CR-SM-235 hatte `readyThreshold` hereingereicht, damit es nur
|
|
18
|
+
* EINEN Wert fuer „ist diese Dimension zu schwach?" gibt — das Urteil stand danach trotzdem
|
|
19
|
+
* zweimal, hier als `ready` und beim Konsumenten (graphcode generate.ts). Messen und Urteilen
|
|
20
|
+
* sind getrennt: diese Funktion misst, der Konsument urteilt mit seiner Config.
|
|
21
21
|
*/
|
|
22
|
-
export function computeReadiness(graph, policy
|
|
22
|
+
export function computeReadiness(graph, policy) {
|
|
23
23
|
const allViolations = evaluateAllRules(graph, policy);
|
|
24
24
|
// Group violations by dimension
|
|
25
25
|
const violationsByDim = new Map();
|
|
@@ -83,8 +83,6 @@ export function computeReadiness(graph, policy, readyThreshold) {
|
|
|
83
83
|
violations,
|
|
84
84
|
applicable,
|
|
85
85
|
coreApplicable,
|
|
86
|
-
// Nicht messbar ist nicht bereit — nie `true` bei `null`.
|
|
87
|
-
ready: score !== null && score >= readyThreshold,
|
|
88
86
|
};
|
|
89
87
|
});
|
|
90
88
|
// CR-SM-237: `overallScore` faellt — das ungewichtete Mittel dieser Scores, von keinem
|
|
@@ -140,13 +138,25 @@ export function coreTypesOf(dim) {
|
|
|
140
138
|
for (const type of new Set(d.domain))
|
|
141
139
|
seenIn[type] = (seenIn[type] ?? 0) + 1;
|
|
142
140
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
|
|
141
|
+
// CR-SM-328: die RELATIVE Mehrheit mit eindeutigem Sieger, nicht die absolute.
|
|
142
|
+
//
|
|
143
|
+
// Die absolute Mehrheit (> n/2) haengt an einer Zahl, die mit dem KATALOG waechst und mit
|
|
144
|
+
// dem Gegenstand der Dimension nichts zu tun hat. Gemessen an `ver`: sieben Regeln mit TEST
|
|
145
|
+
// in vier ergaben 4 > 3,5 und den Kern [TEST]; nach CR-SM-319 (R-32, domain SCHEMA) waren es
|
|
146
|
+
// acht Regeln mit TEST in vier, also 4 > 4 = falsch — der Fallback machte ALLES zum Kern und
|
|
147
|
+
// legte den Waechter dieser Dimension still, ohne dass sich an `ver` selbst etwas geaendert
|
|
148
|
+
// haette. Eine einzige neue Regel mit fremder Grundgesamtheit genuegte.
|
|
149
|
+
//
|
|
150
|
+
// Die relative Mehrheit beantwortet dieselbe Frage stabil: welcher Typ wird von den MEISTEN
|
|
151
|
+
// Regeln dieser Dimension geprueft. Sie ist eine Abschwaechung, keine Umkehr — eine absolute
|
|
152
|
+
// Mehrheit IST immer das eindeutige Maximum, das Ergebnis kann sich also nur dort aendern,
|
|
153
|
+
// wo vorher der Fallback stand.
|
|
154
|
+
const top = Math.max(...Object.values(seenIn));
|
|
155
|
+
const core = Object.keys(seenIn).filter(type => seenIn[type] === top).sort();
|
|
156
|
+
// Gleichstand an der Spitze: kein Typ ist DER Gegenstand, also ist der Kern ALLES, was die
|
|
157
|
+
// Dimension prueft. Der Waechter greift dann nur noch, wenn auch `applicable` 0 waere —
|
|
158
|
+
// Verhalten wie vor CR-SM-270. Lieber nicht greifen als am falschen Ort greifen.
|
|
159
|
+
return core.length === 1 ? core : [...new Set(defs.flatMap(d => d.domain))].sort();
|
|
150
160
|
}
|
|
151
161
|
function computeCoreApplicable(countByType) {
|
|
152
162
|
const result = {};
|
package/dist/rule-classify.js
CHANGED
|
@@ -53,6 +53,9 @@ export const MT_IRRELEVANT_POLICY = {
|
|
|
53
53
|
export const CLASS_MAP = {
|
|
54
54
|
// --- Operators: fix adds a trace/element (topology-changing) ---------------
|
|
55
55
|
'R-01': { class: 'Operator', rationale: 'add verify trace REQ←TEST' },
|
|
56
|
+
// CR-SM-328 (nachgezogen aus CR-SM-319): derselbe Fix wie R-01, nur am SCHEMA —
|
|
57
|
+
// eine `verify`-Kante kommt hinzu, die Topologie bewegt sich.
|
|
58
|
+
'R-32': { class: 'Operator', rationale: 'add verify trace SCHEMA←TEST — the contract test is missing, not mis-shaped' },
|
|
56
59
|
'R-02': { class: 'Operator', rationale: 'add satisfy trace FUNC→REQ' },
|
|
57
60
|
'R-05': { class: 'Operator', rationale: 'add verify trace TEST→REQ' },
|
|
58
61
|
'R-10': { class: 'Operator', rationale: 'add io traces to complete the FLOW' },
|
|
@@ -73,6 +76,10 @@ export const CLASS_MAP = {
|
|
|
73
76
|
'FC-02': { class: 'Operator', rationale: 'add FCHAIN via compose trace to leaf UC' },
|
|
74
77
|
'SC-02': { class: 'Operator', rationale: 'link FLOW→SCHEMA via relation trace' },
|
|
75
78
|
'IO-01': { class: 'Operator', rationale: 'add FLOW element + io traces between the FUNC pair' },
|
|
79
|
+
// CR-SM-309: IO-02 (contracts 20) — die Reparatur ist ein Auftrennen je Verbindung. Welcher
|
|
80
|
+
// Produzent welche Konsumenten behaelt, steht in keinem Feld, sondern im Code; ein Operator
|
|
81
|
+
// daraus waere geraten (Praezedenz RC-*, CR-SM-305).
|
|
82
|
+
'IO-02': { class: 'Constraint', rationale: 'one producer per FLOW — the split per connection needs code evidence, no deterministic operator' },
|
|
76
83
|
// CR-GC-366: beide Fixes fuegen eine Trace hinzu, also Operator wie R-15 (compose) und R-10 (io).
|
|
77
84
|
'R-30': { class: 'Operator', rationale: 'add compose trace FCHAIN→FUNC to bind the function into a chain' },
|
|
78
85
|
'R-31': { class: 'Operator', rationale: 'add io traces FLOW→FUNC / FUNC→FLOW to wire the function up' },
|
|
@@ -81,7 +88,7 @@ export const CLASS_MAP = {
|
|
|
81
88
|
'FM-02': { class: 'Operator', rationale: 'create mitigation REQ + compose trace' },
|
|
82
89
|
'FM-03': { class: 'Operator', rationale: 'add TEST(passed) + verify trace to risk REQ' },
|
|
83
90
|
// --- Constraints: remove/repair/reduce, or attribute/text-only -------------
|
|
84
|
-
'R-04': { class: 'Constraint', rationale: 'module too
|
|
91
|
+
'R-04': { class: 'Constraint', rationale: 'module boundary too wide — merge contracts or move functions, non-additive' },
|
|
85
92
|
'R-08': { class: 'Constraint', rationale: 'repair dangling trace endpoint' },
|
|
86
93
|
'R-12': { class: 'Constraint', rationale: 'break dependency cycle — remove an edge' },
|
|
87
94
|
'R-18': { class: 'Constraint', rationale: 'invalid trace pattern — change/remove trace' },
|
|
@@ -95,11 +102,15 @@ export const CLASS_MAP = {
|
|
|
95
102
|
'RD-02': { class: 'Constraint', rationale: 'decomposition consistency — repair existing' },
|
|
96
103
|
'RD-03': { class: 'Constraint', rationale: 'premature decomposition — remove children' },
|
|
97
104
|
'RD-04': { class: 'Constraint', rationale: 'decomposition breadth 7±2 — split level, non-additive' },
|
|
105
|
+
'RD-05': { class: 'Constraint', rationale: 'degenerate level (< min children) — dissolve into parent, non-additive' },
|
|
98
106
|
'MS-02': { class: 'Constraint', rationale: 'dangling dependency — fix relation target' },
|
|
99
107
|
'UC-04': { class: 'Constraint', rationale: 'goal = description text — no topology change' },
|
|
100
108
|
'FC-03': { class: 'Constraint', rationale: 'flatten chain — move nested funcs' },
|
|
101
109
|
'MT-01': { class: 'Constraint', rationale: 'instability threshold — restructure' },
|
|
102
110
|
'MT-02': { class: 'Constraint', rationale: 'cohesion (LCOM4) threshold — restructure' },
|
|
111
|
+
// CR-SM-327: wie MT-02 — der Fix zerlegt oder verdrahtet um, er fuegt keine einzelne
|
|
112
|
+
// Kante hinzu, die der Operator raten koennte.
|
|
113
|
+
'MT-04': { class: 'Constraint', rationale: 'split the whitebox or wire its groups — a restructuring, not one additive trace' },
|
|
103
114
|
'BQ-01': { class: 'Constraint', rationale: 'unambiguous — text quality' },
|
|
104
115
|
'BQ-02': { class: 'Constraint', rationale: 'verifiable — text quality' },
|
|
105
116
|
'BQ-04': { class: 'Constraint', rationale: 'necessary — text/scope quality' },
|
|
@@ -141,6 +152,7 @@ export const CLASS_MAP = {
|
|
|
141
152
|
'RC-04': { class: 'Constraint', rationale: 'SCHEMA wird an seiner Schnittstelle nicht geparst — Codeänderung' },
|
|
142
153
|
'RC-05': { class: 'Constraint', rationale: 'Import quert eine undokumentierte Modulgrenze — Import entfernen oder Fluss modellieren', ambiguous: true },
|
|
143
154
|
'RC-06': { class: 'Constraint', rationale: 'externe Bindung nennt ein nicht deklariertes Paket — dependency oder realRef' },
|
|
155
|
+
'RC-07': { class: 'Constraint', rationale: 'CR-Knoten widerspricht docs/cr — Status angleichen oder Knoten anlegen, das Verzeichnis entscheidet' },
|
|
144
156
|
};
|
|
145
157
|
const UNKNOWN = { class: 'Constraint', rationale: 'unclassified — not in CLASS_MAP', ambiguous: true };
|
|
146
158
|
/** Classify a single rule id (falls back to ambiguous-unknown). */
|
package/dist/steer.d.ts
CHANGED
|
@@ -47,10 +47,11 @@
|
|
|
47
47
|
* weiter zählt, was fehlt. Die beiden sind komplementär: readiness misst ABDECKUNG (wie
|
|
48
48
|
* viele Stellen sind erledigt), dieser Score AUSPRÄGUNG (wie schlimm ist die schlimmste
|
|
49
49
|
* offene). Beide lesen denselben Regelstrom.
|
|
50
|
-
* 3. Die MOD-Whitebox hat keine eigene Randbreiten-Regel
|
|
51
|
-
*
|
|
52
|
-
* `
|
|
53
|
-
*
|
|
50
|
+
* 3. ~~Die MOD-Whitebox hat keine eigene Randbreiten-Regel.~~ GESCHLOSSEN mit CR-SM-312: R-04
|
|
51
|
+
* misst jetzt allein den Modulrand, gegen dieselbe Schwelle wie BW-02, und steht unten in
|
|
52
|
+
* `STEER_RULES`. Vorher sah R-04 den Rand nur zusammen mit der Grösse, also war ein kleines
|
|
53
|
+
* Modul mit breitem Rand stumm (gemessen: `MOD-kernel-measure` 9 Verträge bei 7 Funktionen,
|
|
54
|
+
* `mod_api_server_ts` 17). Die Grösse ist seit CR-SM-311 RD-04s Frage.
|
|
54
55
|
*/
|
|
55
56
|
import type { RuleViolation } from '@sigloch/contracts/se';
|
|
56
57
|
/**
|
|
@@ -61,7 +62,7 @@ import type { RuleViolation } from '@sigloch/contracts/se';
|
|
|
61
62
|
* Bewusst eine geschlossene Liste und NICHT aus `context.value !== undefined` abgeleitet: eine
|
|
62
63
|
* künftige Regel, die zufällig eine Zahl mitführt, würde sonst still zum Steuersignal.
|
|
63
64
|
*/
|
|
64
|
-
export declare const STEER_RULES: readonly ["RD-04", "BW-02", "CR-01", "MT-02"];
|
|
65
|
+
export declare const STEER_RULES: readonly ["RD-04", "BW-02", "R-04", "CR-01", "MT-02"];
|
|
65
66
|
/** Der Ausgleichsterm. Klein genug, dass er ein echtes Maximum nie überstimmt. */
|
|
66
67
|
export declare const EPS_AUGMENT = 0.001;
|
|
67
68
|
export interface SteerScore {
|
package/dist/steer.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* 305 Abhaengigkeiten (11 %), 132 von 146 Modulen bei null, Schwanz bis 6. Lokal, gerichtet,
|
|
27
27
|
* budgetierbar, nicht entartet: drei von drei.
|
|
28
28
|
*/
|
|
29
|
-
export const STEER_RULES = ['RD-04', 'BW-02', 'CR-01', 'MT-02'];
|
|
29
|
+
export const STEER_RULES = ['RD-04', 'BW-02', 'R-04', 'CR-01', 'MT-02'];
|
|
30
30
|
/** Der Ausgleichsterm. Klein genug, dass er ein echtes Maximum nie überstimmt. */
|
|
31
31
|
export const EPS_AUGMENT = 1e-3;
|
|
32
32
|
const NEUTRAL = { worst: 0, worstAt: null, mean: 0, score: 0, measured: 0 };
|