@sigloch/contracts 6.3.0 → 10.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.
Files changed (41) hide show
  1. package/dist/se/ao-rules.d.ts +12 -12
  2. package/dist/se/ao-rules.js +88 -225
  3. package/dist/se/conformance-rules.d.ts +28 -0
  4. package/dist/se/conformance-rules.js +40 -17
  5. package/dist/se/cr-quality-rules.js +75 -58
  6. package/dist/se/evaluate-all.d.ts +4 -2
  7. package/dist/se/evaluate-all.js +40 -24
  8. package/dist/se/fchain-quality-rules.d.ts +0 -1
  9. package/dist/se/fchain-quality-rules.js +0 -44
  10. package/dist/se/flat-graph.d.ts +9 -1
  11. package/dist/se/flat-graph.js +15 -6
  12. package/dist/se/format-e-parser.d.ts +14 -2
  13. package/dist/se/format-e-parser.js +33 -9
  14. package/dist/se/grammar-snapshot.d.ts +10 -7
  15. package/dist/se/grammar-snapshot.js +172 -27
  16. package/dist/se/index.d.ts +4 -3
  17. package/dist/se/index.js +4 -3
  18. package/dist/se/meta-model.d.ts +99 -7
  19. package/dist/se/meta-model.js +155 -14
  20. package/dist/se/metric-rules.d.ts +20 -1
  21. package/dist/se/metric-rules.js +97 -58
  22. package/dist/se/module-crossings.d.ts +102 -0
  23. package/dist/se/module-crossings.js +196 -0
  24. package/dist/se/near-duplicate-rules.d.ts +16 -24
  25. package/dist/se/near-duplicate-rules.js +21 -92
  26. package/dist/se/ontology.d.ts +32 -47
  27. package/dist/se/ontology.js +56 -13
  28. package/dist/se/policy.d.ts +6 -0
  29. package/dist/se/policy.js +53 -2
  30. package/dist/se/quality-rules.d.ts +18 -0
  31. package/dist/se/quality-rules.js +68 -12
  32. package/dist/se/readiness.d.ts +7 -5
  33. package/dist/se/readiness.js +40 -22
  34. package/dist/se/rules.d.ts +6 -7
  35. package/dist/se/rules.js +358 -128
  36. package/dist/se/schema-quality-rules.d.ts +0 -1
  37. package/dist/se/schema-quality-rules.js +7 -28
  38. package/dist/se/similarity.d.ts +61 -0
  39. package/dist/se/similarity.js +116 -0
  40. package/dist/se/uc-quality-rules.js +31 -12
  41. package/package.json +3 -2
@@ -1,16 +1,55 @@
1
1
  // ---------------------------------------------------------------------------
2
- // CR-R01: CR must have at least one outgoing relation trace
2
+ // CR-R01: ein offener CR nennt, WAS er aendert (CR-SM-295)
3
+ //
4
+ // Bis hierher waren es zwei Regeln, und beide zielten daneben. CR-R01 verlangte
5
+ // IRGENDEINE relation-Kante — und akzeptierte damit einen CR, der nur an einem
6
+ // Meilenstein haengt: das ist ein Termin, kein Umfang. Ueber 514 CR-Knoten in 19
7
+ // Familiengraphen feuerte sie 5-mal, waehrend 49 CRs ausschliesslich auf ein MS zeigten
8
+ // und unbeanstandet blieben. CR-R04 verlangte umgekehrt einen FUNC — zu eng: 21 CRs
9
+ // meldeten, und ein grosser Teil davon aendert Daten, Doku oder Konfiguration und
10
+ // beruehrt zu Recht keine Funktion.
11
+ //
12
+ // Die tragende Frage ist keine von beiden, sondern: nennt dieser CR ein Element, das er
13
+ // AENDERT? Umfang sind FUNC, MOD, SCHEMA, REQ und UC. MS ist Terminplanung und zaehlt
14
+ // nicht — MS-03 stellt diese Frage getrennt und bleibt unberuehrt.
15
+ //
16
+ // Grundgesamtheit wie bei CR-R04 (CR-SM-255) — nur was noch steuerbar ist. An einem
17
+ // geschlossenen CR ist die Frage Archaeologie: was er beruehrt hat, steht im Commit.
18
+ //
19
+ // Die Menge ist aber UMGEDREHT formuliert: nicht "open oder in-progress", sondern "nicht
20
+ // abgeschlossen". Der Grund ist gemessen — im Bestand tragen CRs die Status `done` (463),
21
+ // `open` (34), `planned` (12), `rejected` (2), `dropped` (1) und keinen (2). `planned`
22
+ // steht in keinem Enum der Ontologie, wird aber real geschrieben; eine Positivliste haette
23
+ // diese zwoelf CRs stillschweigend uebersprungen. Eine Regel, die durch einen ihr
24
+ // unbekannten Statuswert stumm wird, ist von einer bestandenen Pruefung nicht zu
25
+ // unterscheiden — dieselbe Fail-open-Klasse wie ND-01/ND-02 vor CR-SM-286.
26
+ //
27
+ // Ein CR ganz OHNE status ist erst recht nicht abgeschlossen.
28
+ //
29
+ // Gemessen vor der Umstellung: von 514 CRs tragen 54 keinen Umfangsbezug — davon sind
30
+ // **0 offen**, 52 `done` und 2 ohne Status. Die neue Fassung feuert am Bestand also auf
31
+ // hoechstens 2 und laesst die Historie unangetastet; ihre Wirkung beginnt beim naechsten
32
+ // CR, der geschrieben wird.
3
33
  // ---------------------------------------------------------------------------
34
+ /** Elementtypen, die einen Aenderungsumfang darstellen — MS gehoert bewusst nicht dazu. */
35
+ const SCOPE_TYPES = new Set(['FUNC', 'MOD', 'SCHEMA', 'REQ', 'UC']);
36
+ /** Abgeschlossen heisst: nicht mehr steuerbar. Alles andere ist Grundgesamtheit. */
37
+ const CLOSED_STATUS = new Set(['done', 'dropped', 'rejected']);
4
38
  function crMustTrack(graph) {
5
- const crs = graph.elements.filter(e => e.type === 'CR');
39
+ const typeOf = new Map(graph.elements.map(e => [e.id, e.type]));
40
+ const crs = graph.elements.filter(e => {
41
+ if (e.type !== 'CR')
42
+ return false;
43
+ return !CLOSED_STATUS.has(String(e.attributes?.status ?? ''));
44
+ });
6
45
  return crs
7
- .filter(cr => !graph.traces.some(t => t.source === cr.id && t.type === 'relation'))
46
+ .filter(cr => !graph.traces.some(t => t.source === cr.id && t.type === 'relation' && SCOPE_TYPES.has(typeOf.get(t.target) ?? '')))
8
47
  .map(cr => ({
9
48
  rule_id: 'CR-R01',
10
49
  severity: 'error',
11
50
  element_id: cr.id,
12
- message: `${cr.id} has no relation traces (tracks nothing)`,
13
- fix_hint: 'Add relation traces to affected UC, REQ, FUNC, or MOD elements',
51
+ message: `${cr.id} names no scope (no relation to FUNC/MOD/SCHEMA/REQ/UC)`,
52
+ fix_hint: 'Add a relation trace to the FUNC, MOD, SCHEMA, REQ or UC this CR changes — a milestone alone is a date, not a scope',
14
53
  context: {
15
54
  element_type: cr.type,
16
55
  element_name: cr.name,
@@ -63,71 +102,50 @@ function noConcurrentMutation(graph) {
63
102
  targetToCrs.set(tgt, list);
64
103
  }
65
104
  }
66
- const violations = [];
67
- const seen = new Set();
68
- for (const [target, crIds] of targetToCrs) {
105
+ // CR-SM-304 EIN Befund je Konflikt-MENGE, aber an einem BERECHENBAREN Element.
106
+ //
107
+ // Die Ein-Befund-Regel bleibt: dieselben zwei offenen CRs, die sich an drei Knoten begegnen,
108
+ // sind EIN Koordinationsproblem und nicht drei (Gate 4, Doppelzaehlung). Falsch war, woher der
109
+ // Anker kam: `targetToCrs` folgt der TRACE-Reihenfolge, also entschied die Array-Ordnung im
110
+ // Graphen, welches Ziel meldet — "kein erster Treffer" ist Gate 5 woertlich, und dieselbe
111
+ // Klasse wie der offene R-28-Fall (CR-SM-245). Gemessen am graphcode-Selbstmodell wechselte
112
+ // der Befund bei umgedrehter Reihenfolge von FUNC-graph-suggest auf MS-9-generation; ein
113
+ // Reseed aus dem Kuzu-Store reichte, damit eine Vorher/Nachher-Bilanz bei NULL Zuegen
114
+ // "einen geschlossen, einen neu" meldete.
115
+ //
116
+ // Zweiter Teil desselben Defekts: das unterdrueckte Ziel wurde nicht nur nicht angekert, es
117
+ // wurde gar nicht genannt. Wer koordinieren soll, braucht die vollstaendige Liste — sie steht
118
+ // jetzt in der Meldung und als `also_affects` im Kontext.
119
+ const bySet = new Map();
120
+ for (const target of [...targetToCrs.keys()].sort()) {
121
+ const crIds = [...targetToCrs.get(target)].sort();
69
122
  if (crIds.length < 2)
70
123
  continue;
71
- const key = crIds.sort().join(',');
72
- if (seen.has(key))
73
- continue;
74
- seen.add(key);
124
+ const key = crIds.join(',');
125
+ bySet.set(key, [...(bySet.get(key) ?? []), target]);
126
+ }
127
+ const violations = [];
128
+ for (const [key, targets] of bySet) {
129
+ const crIds = key.split(',');
130
+ const [anchor, ...also] = targets;
131
+ const el = graph.elements.find(e => e.id === anchor);
75
132
  violations.push({
76
133
  rule_id: 'CR-R03',
77
134
  severity: 'warning',
78
- element_id: target,
79
- message: `${target} is tracked by ${crIds.length} open CRs: ${crIds.join(', ')}`,
135
+ element_id: anchor,
136
+ message: `${anchor} is tracked by ${crIds.length} open CRs: ${crIds.join(', ')}` +
137
+ (also.length > 0 ? ` — the same CRs also track ${also.join(', ')}` : ''),
80
138
  fix_hint: 'Coordinate changes to avoid merge conflicts',
81
139
  context: {
82
- element_type: graph.elements.find(e => e.id === target)?.type,
83
- element_name: graph.elements.find(e => e.id === target)?.name,
140
+ element_type: el?.type,
141
+ element_name: el?.name,
142
+ also_affects: also,
84
143
  },
85
144
  });
86
145
  }
87
146
  return violations;
88
147
  }
89
148
  // ---------------------------------------------------------------------------
90
- // CR-R04: an OPEN CR must have at least one relation→FUNC trace (CR-207,
91
- // Grundgesamtheit verengt in CR-SM-255)
92
- //
93
- // "Welche Funktionen fasst dieser CR an" ist eine PLANUNGSfrage — sie steuert, bevor
94
- // gebaut wird. An einem geschlossenen CR ist sie Archaeologie: was er beruehrt hat,
95
- // steht im Commit und im Diff, nicht im Graphen. Wer die Kanten nachtraeglich zieht,
96
- // raet, und erfundene Praezision ist teurer als eine fehlende Kante.
97
- //
98
- // Gemessen am graphcode-Selbstmodell (graphVersion 171): 41 meldende CRs, davon 40
99
- // `done` und 1 `dropped` — kein einziger offener. Die Regel feuerte ausschliesslich
100
- // dort, wo sie nichts mehr steuern kann, und trug damit 41 unbearbeitbare Befunde.
101
- //
102
- // Die Statusmenge ist woertlich die von CR-R03 (s. o.): dieselbe Frage nach "noch in
103
- // Arbeit", dieselbe Antwort. CR-R01 ("ein CR trackt ueberhaupt etwas") bleibt fuer
104
- // ALLE CRs gueltig — nur die Verschaerfung "und zwar einen FUNC" ist Planung.
105
- // ---------------------------------------------------------------------------
106
- function crMustHaveFunc(graph) {
107
- // Ein CR ganz OHNE status ist kein geschlossener CR — die Regel darf nicht durch ein
108
- // fehlendes Attribut stumm werden.
109
- const crs = graph.elements.filter(e => {
110
- if (e.type !== 'CR')
111
- return false;
112
- const status = e.attributes?.status;
113
- return status === undefined || status === 'open' || status === 'in-progress';
114
- });
115
- return crs
116
- .filter(cr => !graph.traces.some(t => t.source === cr.id && t.type === 'relation' &&
117
- graph.elements.some(e => e.id === t.target && e.type === 'FUNC')))
118
- .map(cr => ({
119
- rule_id: 'CR-R04',
120
- severity: 'warning',
121
- element_id: cr.id,
122
- message: `${cr.id} has no relation→FUNC trace (no implementation scope)`,
123
- fix_hint: 'Add CR→FUNC [relation] traces to define which functions this CR changes',
124
- context: {
125
- element_type: cr.type,
126
- element_name: cr.name,
127
- },
128
- }));
129
- }
130
- // ---------------------------------------------------------------------------
131
149
  // MS-03: CR should have a CR→MS [relation] trace (CR-207)
132
150
  // ---------------------------------------------------------------------------
133
151
  function crShouldHaveMilestone(graph) {
@@ -159,7 +177,6 @@ export const CR_RULES = [
159
177
  // (= alle Elemente) ist die einzige Menge, aus der der Zielknoten garantiert stammt.
160
178
  // Damit ist sie nach R-08/R-18 die dritte 'all'-Regel — bewusst, nicht vergessen.
161
179
  { id: 'CR-R03', name: 'No concurrent mutation', severity: 'warning', evaluate: noConcurrentMutation, domain: ['all'] },
162
- { id: 'CR-R04', name: 'Open CR must have FUNC', severity: 'warning', evaluate: crMustHaveFunc, domain: ['CR'] },
163
180
  { id: 'MS-03', name: 'CR without milestone', severity: 'info', evaluate: crShouldHaveMilestone, domain: ['CR'] },
164
181
  ];
165
182
  // CR-SM-236: `policy` wird durchgereicht, auch wo diese Familie heute keine Schwelle hat —
@@ -13,14 +13,16 @@ import type { MetricPolicy } from './policy.js';
13
13
  * hier statt eine eigene Tabelle zu fuehren. Eine zweite Tabelle kann nicht hinterherhinken,
14
14
  * wenn es keine zweite gibt.
15
15
  */
16
+ /** Profile groupings — see CATALOGS. */
17
+ export type ProfileId = 'default' | 'se' | 'coding';
16
18
  export declare const ALL_RULE_DEFS: ReadonlyArray<{
17
19
  id: string;
18
20
  name: string;
19
21
  severity: 'error' | 'warning' | 'info';
20
22
  domain: readonly string[];
23
+ /** CR-SM-285: das Profil reist mit der Regel, statt aus ihrer ID geraten zu werden. */
24
+ profile: Exclude<ProfileId, 'default'>;
21
25
  }>;
22
- /** Profile groupings derived from rule prefixes. */
23
- export type ProfileId = 'default' | 'se' | 'coding';
24
26
  export declare function getRuleDefsForProfile(profile: ProfileId): typeof ALL_RULE_DEFS;
25
27
  /**
26
28
  * Evaluate all rules against a graph. Single call replaces the individual evaluator calls.
@@ -3,6 +3,7 @@ import { SC_RULES, evaluateSCRules } from './schema-quality-rules.js';
3
3
  import { UC_RULES, evaluateUCRules } from './uc-quality-rules.js';
4
4
  import { FC_RULES, evaluateFCRules } from './fchain-quality-rules.js';
5
5
  import { MT_RULES, evaluateMTRules } from './metric-rules.js';
6
+ import { toEvaluableGraph } from './flat-graph.js';
6
7
  import { FM_RULES, evaluateFMRules } from './fmea-rules.js';
7
8
  import { VIEW_RULES, evaluateViewRules } from './view-rules.js';
8
9
  import { CR_RULES, evaluateCRRules } from './cr-quality-rules.js';
@@ -11,33 +12,38 @@ import { AO_RULES, evaluateAORules } from './ao-rules.js';
11
12
  import { BQ_RULES, evaluateBQRules } from './quality-rules.js';
12
13
  import { AF_RULES, evaluateAFRules } from './analysis-freshness-rules.js';
13
14
  /**
14
- * All prescribed rule definitions (single source of truth for the catalog).
15
+ * CR-SM-285: das Profil haengt am KATALOG, nicht am ID-Praefix.
15
16
  *
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.
17
+ * Bis hierher ordnete `SE_PREFIXES`/`CODING_PREFIXES` eine Regel ueber den Anfang ihrer ID zu.
18
+ * Drei dokumentierte Ausfaelle derselben Klasse: `RD-` (CR-SM-221 `'RD-01'.startsWith('R-')`
19
+ * ist false, die Zerlegungsregeln liefen nie im se-Profil), `MS-` (CR-SM-245 fehlte in BEIDEN
20
+ * Listen, die Dimension `ms` hatte im se-Profil keine einzige zaehlende Regel), `BW-`
21
+ * (CR-SM-283). Jede neue Regel-ID war ein potenzieller vierter.
22
+ *
23
+ * Ein Katalog weiss, wozu er gehoert; eine Zeichenkette weiss es nicht. Neue Regeln erben das
24
+ * Profil ihres Katalogs automatisch — und ein NEUER Katalog muss hier eingetragen werden, sonst
25
+ * bricht `ALL_RULE_DEFS` schon beim Typcheck (jeder Eintrag braucht sein Profil).
20
26
  */
21
- export const ALL_RULE_DEFS = [
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 }));
25
- // CR-SM-221: 'RD-' was missing — 'RD-01'.startsWith('R-') is false, so the
26
- // decomposition rules ran in `default` only and never in the `se` profile.
27
- // CR-SM-245: 'MS-' fehlte hier UND in CODING_PREFIXES — MS-01/02/03 fielen aus beiden Profilen
28
- // und liefen nur im 'default'-Lauf. Die Dimension `ms` wird von genau vier Regeln getragen
29
- // (MS-01/02/03 + AF-05); AF-05 ist eine `domain: ['graph']`-Regel und traegt per CR-SM-239
30
- // keinen Nenner bei. Im se-Profil hatte `ms` damit keine einzige zaehlende Regel — ein leerer
31
- // Topic-Score und drei fehlende SRR-Legs. Zweiter Fall derselben Klasse nach 'RD-' (CR-SM-221),
32
- // jetzt vom Profil-Test in se-grammar-invariant.test.ts abgedeckt.
33
- const SE_PREFIXES = ['R-', 'RD-', 'UC-', 'FC-', 'SC-', 'MT-', 'CR-', 'AO-', 'FM-', 'NFR-', 'RT-', 'PH-', 'CA-', 'IO-', 'VR-', 'CL-', 'AF-', 'MS-'];
34
- const CODING_PREFIXES = ['BQ-', 'ND-'];
27
+ const CATALOGS = [
28
+ { profile: 'se', rules: V3_RULES },
29
+ { profile: 'se', rules: UC_RULES },
30
+ { profile: 'se', rules: FC_RULES },
31
+ { profile: 'se', rules: SC_RULES },
32
+ { profile: 'se', rules: MT_RULES },
33
+ { profile: 'se', rules: CR_RULES },
34
+ { profile: 'se', rules: AO_RULES },
35
+ { profile: 'se', rules: FM_RULES },
36
+ { profile: 'se', rules: VIEW_RULES },
37
+ { profile: 'se', rules: AF_RULES },
38
+ // Sprach-/Textqualitaet statt SE-Struktur das ist die Trennlinie, die die Praefixliste meinte.
39
+ { profile: 'coding', rules: BQ_RULES },
40
+ { profile: 'coding', rules: ND_RULES },
41
+ ];
42
+ export const ALL_RULE_DEFS = CATALOGS.flatMap(({ profile, rules }) => rules.map(r => ({ id: r.id, name: r.name, severity: r.severity, domain: r.domain, profile })));
35
43
  export function getRuleDefsForProfile(profile) {
36
- if (profile === 'se')
37
- return ALL_RULE_DEFS.filter(r => SE_PREFIXES.some(p => r.id.startsWith(p)));
38
- if (profile === 'coding')
39
- return ALL_RULE_DEFS.filter(r => CODING_PREFIXES.some(p => r.id.startsWith(p)));
40
- return ALL_RULE_DEFS;
44
+ if (profile === 'default')
45
+ return ALL_RULE_DEFS;
46
+ return ALL_RULE_DEFS.filter(r => r.profile === profile);
41
47
  }
42
48
  /**
43
49
  * Evaluate all rules against a graph. Single call replaces the individual evaluator calls.
@@ -47,6 +53,16 @@ export function getRuleDefsForProfile(profile) {
47
53
  * `DEFAULT_METRIC_POLICY` sichtbar an der Aufrufstelle.
48
54
  */
49
55
  export function evaluateAllRules(graph, policy) {
56
+ // CR-SM-284: die Hebung der flach committeten SSOT laeuft HIER, nicht beim Aufrufer.
57
+ //
58
+ // `toEvaluableGraph` gibt es seit CR-SM-258 — und sie wurde von keinem Produktionspfad und
59
+ // keinem Messskript gerufen, nur aus Tests. Eine Korrektur, die man rufen DARF statt MUSS, ist
60
+ // keine: an graphcode erzeugte die flache Lesart 158 Phantom-Befunde (R-19 124, R-20 115,
61
+ // R-26 36, CR-R04 42) und verdeckte zugleich 156 ECHTE Fehler (CR-R02, severity error).
62
+ //
63
+ // Idempotent und identitaetserhaltend (s. dort), also eine Normalisierung am einzigen Eingang
64
+ // und kein Fallback: ein bereits genesteter Graph geht unveraendert und uneingepackt durch.
65
+ graph = toEvaluableGraph(graph);
50
66
  return [
51
67
  ...evaluateRules(graph, policy),
52
68
  ...evaluateBQRules(graph, policy),
@@ -4,7 +4,6 @@
4
4
  import type { OntologyGraph } from './ontology.js';
5
5
  import type { RuleDefinition, RuleViolation } from './rules.js';
6
6
  import type { MetricPolicy } from './policy.js';
7
- export declare function fc01ActorBoundary(graph: OntologyGraph): RuleViolation[];
8
7
  export declare function fc02LeafUcHasFchain(graph: OntologyGraph): RuleViolation[];
9
8
  export declare function fc03FchainFlat(graph: OntologyGraph): RuleViolation[];
10
9
  export declare function fc04ActorBounded(graph: OntologyGraph): RuleViolation[];
@@ -1,48 +1,5 @@
1
1
  import { indexOf } from './graph-index.js';
2
2
  // ---------------------------------------------------------------------------
3
- // FC-01: FCHAIN must have Actor boundary (input or output via FLOW→ACTOR io)
4
- // ---------------------------------------------------------------------------
5
- export function fc01ActorBoundary(graph) {
6
- // CR-SM-264: dieselbe Frage, einmal statt je Kette neu.
7
- //
8
- // Die alte Fassung war die verschachtelte Form, die UC-02 kubisch gemacht hat (CR-SM-261):
9
- // je FCHAIN alle Traces, darin je io-Kante noch einmal alle Traces, darin je Treffer alle
10
- // Elemente — `FCHAIN x FUNC x T x T x E`. Im Profil nach Teil a war FC-01 mit 6,3 % die
11
- // teuerste FCHAIN-Regel.
12
- //
13
- // Beide Zweige fragen in Wahrheit DASSELBE: "beruehrt dieses Element eine io-Kante, deren
14
- // anderes Ende ein ACTOR ist?" Einmal fuer den Zwischenknoten der Kettenglieder, einmal
15
- // direkt fuer den Eltern-UC. Eine Menge beantwortet beide.
16
- const idx = indexOf(graph);
17
- const actorAdjacent = new Set();
18
- for (const t of idx.tracesOfType('io')) {
19
- if (idx.typeOf(t.target) === 'ACTOR')
20
- actorAdjacent.add(t.source);
21
- if (idx.typeOf(t.source) === 'ACTOR')
22
- actorAdjacent.add(t.target);
23
- }
24
- return idx.elementsOfType('FCHAIN')
25
- .filter(fc => {
26
- // Mitglieder der Kette — bewusst OHNE Typfilter, wie in der alten Fassung: FC-01 fragt
27
- // nach dem, was komponiert ist, nicht nach dem, was eine FUNC ist (FC-03 tut das).
28
- const memberIds = idx.out(fc.id, 'compose').map(t => t.target);
29
- const hasActorIO = memberIds.some(fid => idx.out(fid, 'io').some(t => actorAdjacent.has(t.target)) ||
30
- idx.in(fid, 'io').some(t => actorAdjacent.has(t.source)));
31
- // Der Umweg ueber den Eltern-UC: dessen eigene ACTOR-io zaehlt auch.
32
- const parentUC = idx.in(fc.id, 'compose').find(t => idx.typeOf(t.source) === 'UC');
33
- const hasDirectActorIO = parentUC !== undefined && actorAdjacent.has(parentUC.source);
34
- return !hasActorIO && !hasDirectActorIO;
35
- })
36
- .map(fc => ({
37
- rule_id: 'FC-01',
38
- severity: 'warning',
39
- element_id: fc.id,
40
- message: `${fc.id} has no actor boundary (no ACTOR io connection)`,
41
- fix_hint: 'Ensure at least one FUNC in the chain connects to an ACTOR via FLOW io',
42
- context: { element_type: fc.type, element_name: fc.name },
43
- }));
44
- }
45
- // ---------------------------------------------------------------------------
46
3
  // FC-02: Leaf UC (no UC→compose→UC) must have at least one FCHAIN
47
4
  // ---------------------------------------------------------------------------
48
5
  export function fc02LeafUcHasFchain(graph) {
@@ -142,7 +99,6 @@ export function fc04ActorBounded(graph) {
142
99
  // Aggregated
143
100
  // ---------------------------------------------------------------------------
144
101
  export const FC_RULES = [
145
- { id: 'FC-01', name: 'FCHAIN has actor boundary', severity: 'warning', evaluate: fc01ActorBoundary, domain: ['FCHAIN'] },
146
102
  { id: 'FC-02', name: 'Leaf UC has FCHAIN', severity: 'warning', evaluate: fc02LeafUcHasFchain, domain: ['UC'] },
147
103
  // CR-SM-243: domain ist FUNC, nicht FCHAIN — die Regel meldet am FUNC mit der
148
104
  // verschachtelten Zerlegung. Die FCHAIN ist der Suchraum, nicht die Grundgesamtheit:
@@ -1,3 +1,11 @@
1
1
  import type { OntologyGraph } from './ontology.js';
2
- /** Hebt eine flach committete SSOT in die Form, die der Live-Gate dem Evaluator gibt. */
2
+ /**
3
+ * Hebt eine flach committete SSOT in die Form, die der Live-Gate dem Evaluator gibt.
4
+ *
5
+ * CR-SM-284: **identitaetserhaltend.** War nichts zu heben — der Normalfall, weil der Live-Gate
6
+ * bereits genestet liefert —, kommt DIESELBE Referenz zurueck. Das ist die Voraussetzung dafuer,
7
+ * dass `evaluateAllRules` die Funktion selbst rufen kann: die WeakMap-Caches der Familie
8
+ * (`indexOf`, `moduleCrossings`, `MEASURE_CACHE`) haengen an der Graph-Identitaet, und ein bei
9
+ * jedem Aufruf neu gebautes Objekt haette sie im Best-of-N-Loop bei jedem Kandidaten gesprengt.
10
+ */
3
11
  export declare function toEvaluableGraph(graph: OntologyGraph): OntologyGraph;
@@ -42,11 +42,20 @@ function nestAttributes(entry, canonical) {
42
42
  attributes.status = entry.status;
43
43
  return { ...top, attributes };
44
44
  }
45
- /** Hebt eine flach committete SSOT in die Form, die der Live-Gate dem Evaluator gibt. */
45
+ /**
46
+ * Hebt eine flach committete SSOT in die Form, die der Live-Gate dem Evaluator gibt.
47
+ *
48
+ * CR-SM-284: **identitaetserhaltend.** War nichts zu heben — der Normalfall, weil der Live-Gate
49
+ * bereits genestet liefert —, kommt DIESELBE Referenz zurueck. Das ist die Voraussetzung dafuer,
50
+ * dass `evaluateAllRules` die Funktion selbst rufen kann: die WeakMap-Caches der Familie
51
+ * (`indexOf`, `moduleCrossings`, `MEASURE_CACHE`) haengen an der Graph-Identitaet, und ein bei
52
+ * jedem Aufruf neu gebautes Objekt haette sie im Best-of-N-Loop bei jedem Kandidaten gesprengt.
53
+ */
46
54
  export function toEvaluableGraph(graph) {
47
- return {
48
- ...graph,
49
- elements: graph.elements.map((e) => nestAttributes(e, TOP_LEVEL_ELEMENT_KEYS)),
50
- traces: graph.traces.map((t) => nestAttributes(t, TOP_LEVEL_TRACE_KEYS)),
51
- };
55
+ const elements = graph.elements.map((e) => nestAttributes(e, TOP_LEVEL_ELEMENT_KEYS));
56
+ const traces = graph.traces.map((t) => nestAttributes(t, TOP_LEVEL_TRACE_KEYS));
57
+ // `nestAttributes` gibt bei bereits genesteten Eintraegen das Original zurueck; sind ALLE
58
+ // unveraendert, war der Graph schon evaluierbar und wird nicht angefasst.
59
+ const untouched = elements.every((e, i) => e === graph.elements[i]) && traces.every((t, i) => t === graph.traces[i]);
60
+ return untouched ? graph : { ...graph, elements, traces };
52
61
  }
@@ -9,8 +9,8 @@
9
9
  *
10
10
  * @sigloch/contracts/se
11
11
  */
12
- import { ElementType } from './ontology.js';
13
- import type { TraceType, OntologyGraph, AttributeSpec } from './ontology.js';
12
+ import { ElementType, TraceType } from './ontology.js';
13
+ import type { OntologyGraph, AttributeSpec, ReqKind } from './ontology.js';
14
14
  export interface FormatEOperation {
15
15
  type: 'add_node' | 'remove_node' | 'update_node' | 'add_edge' | 'remove_edge' | 'strict_add_node' | 'strict_add_edge';
16
16
  semanticId: string;
@@ -68,6 +68,18 @@ export interface ParseFormatEOptions {
68
68
  * silent skip.
69
69
  */
70
70
  resolveType?: (uid: string) => ElementType | undefined;
71
+ /**
72
+ * CR-SM-266 B: die Kinds eines uid, den dieser Text nicht deklariert. Seit die
73
+ * satisfy-Patterns ein `where` tragen, entscheidet nicht mehr das Typ-Paar allein — ein
74
+ * `MOD -satisfy-> REQ` ist nur gueltig, wenn das REQ strukturelle Kinds traegt.
75
+ *
76
+ * Ohne diesen Resolver sieht der Parser die Kinds eines BESTEHENDEN Knotens nicht und lehnt
77
+ * solche Kanten ab. Das ist Absicht: fehlschlagen und es sagen, nicht raten und durchlassen
78
+ * — dieselbe Entscheidung wie bei `resolveType` ("Without it such a diff is an error, never
79
+ * a silent skip"). Knoten, die DIESER Text anlegt, brauchen ihn nicht; ihre Kinds stehen als
80
+ * `@kinds` in denselben Zeilen.
81
+ */
82
+ resolveKinds?: (uid: string) => readonly ReqKind[] | undefined;
71
83
  }
72
84
  /** Parse a Format E text block into validated operations. */
73
85
  export declare function parseFormatE(input: string, options?: ParseFormatEOptions): FormatEDiff;
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * @sigloch/contracts/se
11
11
  */
12
- import { ElementType, ELEMENT_ATTRIBUTES } from './ontology.js';
12
+ import { ElementType, ELEMENT_ATTRIBUTES, TraceType } from './ontology.js';
13
13
  import { isValidTrace } from './meta-model.js';
14
14
  // ---------------------------------------------------------------------------
15
15
  // Extraction
@@ -23,9 +23,10 @@ export function extractFormatE(llmOutput) {
23
23
  // ---------------------------------------------------------------------------
24
24
  // Parser
25
25
  // ---------------------------------------------------------------------------
26
- const VALID_TRACE_TYPES = new Set([
27
- 'compose', 'io', 'satisfy', 'verify', 'allocate', 'relation', 'produces',
28
- ]);
26
+ // CR-SM-266 D5: ABGELEITET statt abgeschrieben. Die Liste stand hier als zweite Kopie des
27
+ // TraceType-Enums und trug `produces` noch, als es dort schon entfernt war — genau die Drift,
28
+ // die eine doppelte Wahrheit erzeugt. Eine Quelle, keine Pflege.
29
+ const VALID_TRACE_TYPES = new Set(TraceType.options);
29
30
  const OP_PREFIX = {
30
31
  '+': 'add',
31
32
  '-': 'remove',
@@ -109,6 +110,24 @@ export function parseFormatE(input, options = {}) {
109
110
  /** uid → type, from this text's node sections. */
110
111
  const declared = new Map();
111
112
  const typeOf = (uid) => declared.get(uid) ?? options.resolveType?.(uid);
113
+ /**
114
+ * CR-SM-266 B: die Kinds eines uid — erst aus DIESEM Text, dann aus dem Store.
115
+ *
116
+ * `kinds` reist in Format E als `@kinds a,b` und wird erst vom Konsumenten aufs
117
+ * Top-Level-Feld gehoben (graph-api-core, CR-195d). Hier steht es also noch in
118
+ * `op.attributes.kinds`, und genau dort wird es gelesen — sonst saehe eine Mutation, die
119
+ * REQ und satisfy-Kante in EINEM Block anlegt, die eigenen Kinds nicht.
120
+ */
121
+ const kindsOf = (uid) => {
122
+ for (const op of operations) {
123
+ if ('elementType' in op && op.semanticId === uid && op.attributes?.kinds != null) {
124
+ const raw = op.attributes.kinds;
125
+ const list = Array.isArray(raw) ? raw.map(String) : String(raw).split(',');
126
+ return list.map(k => k.trim()).filter(Boolean);
127
+ }
128
+ }
129
+ return options.resolveKinds?.(uid);
130
+ };
112
131
  for (const rawLine of input.split('\n')) {
113
132
  const line = rawLine.trim();
114
133
  if (!line || line.startsWith('//') || line.startsWith('#!'))
@@ -163,7 +182,7 @@ export function parseFormatE(input, options = {}) {
163
182
  if (isEdgeLine || section === 'edges') {
164
183
  const edgeMatch = isEdgeLine ? EDGE_RE.exec(line) : null;
165
184
  if (edgeMatch) {
166
- parseEdge(edgeMatch, typeOf, operations, errors);
185
+ parseEdge(edgeMatch, typeOf, kindsOf, operations, errors);
167
186
  }
168
187
  else {
169
188
  errors.push(`Invalid edge line: "${line}"`);
@@ -223,7 +242,7 @@ function parseNode(m, elementType, ops, errors) {
223
242
  ops.push({ type: 'add_node', semanticId: id, elementType, description: descr });
224
243
  }
225
244
  }
226
- function parseEdge(m, typeOf, ops, errors) {
245
+ function parseEdge(m, typeOf, kindsOf, ops, errors) {
227
246
  const opChar = m[1] || '+';
228
247
  const sourceId = m[2];
229
248
  const traceType = m[3];
@@ -254,7 +273,10 @@ function parseEdge(m, typeOf, ops, errors) {
254
273
  }
255
274
  // CR-148: Normalize before the meta-model check (e.g. FLOW→SCHEMA io → relation)
256
275
  const resolvedTraceType = normalizeTraceType(srcType, tgtType, traceType);
257
- if (!isValidTrace({ source: srcType, target: tgtType, type: resolvedTraceType })) {
276
+ if (!isValidTrace({
277
+ source: srcType, target: tgtType, type: resolvedTraceType,
278
+ sourceKinds: kindsOf(sourceId), targetKinds: kindsOf(targetId),
279
+ })) {
258
280
  errors.push(`Meta-model violation: ${srcType} -${traceType}-> ${tgtType} is not valid`);
259
281
  continue;
260
282
  }
@@ -281,7 +303,8 @@ function parseEdge(m, typeOf, ops, errors) {
281
303
  export function serializeToFormatE(graph) {
282
304
  const lines = [];
283
305
  // Nodes, grouped by type
284
- const modelingElements = graph.elements.filter(el => el.type !== 'SESSION'); // skip audit sessions
306
+ // CR-SM-266 D5: kein SESSION-Skip mehr der Elementtyp existiert nicht.
307
+ const modelingElements = graph.elements;
285
308
  if (modelingElements.length > 0) {
286
309
  lines.push('## Nodes');
287
310
  const byType = new Map();
@@ -313,7 +336,8 @@ export function serializeToFormatE(graph) {
313
336
  }
314
337
  }
315
338
  // Edges
316
- const modelingTraces = graph.traces.filter(t => t.category !== 'audit');
339
+ // CR-SM-266 D5: kein audit-Filter mehr — `Trace.category` existiert nicht.
340
+ const modelingTraces = graph.traces;
317
341
  if (modelingTraces.length > 0) {
318
342
  lines.push('');
319
343
  lines.push('## Edges');
@@ -11,14 +11,17 @@
11
11
  */
12
12
  export declare const GRAMMAR_SNAPSHOT: {
13
13
  readonly versions: {
14
- readonly ontology: "7.0.0";
15
- readonly metaModel: "2.0.0";
16
- readonly rules: "6.3.0";
14
+ readonly ontology: "9.0.0";
15
+ readonly metaModel: "5.0.0";
16
+ readonly rules: "19.0.0";
17
17
  };
18
- readonly elementTypes: readonly ["ACTOR", "CR", "FCHAIN", "FLOW", "FUNC", "MOD", "MS", "REQ", "SCHEMA", "SESSION", "SYS", "TEST", "UC"];
19
- readonly traceTypes: readonly ["allocate", "compose", "io", "produces", "relation", "satisfy", "verify"];
20
- readonly patterns: readonly ["ACTOR -io-> FLOW", "ACTOR -io-> UC", "CR -relation-> FUNC", "CR -relation-> MOD", "CR -relation-> MS", "CR -relation-> REQ", "CR -relation-> UC", "FCHAIN -compose-> FUNC [1..*]", "FCHAIN -satisfy-> REQ", "FLOW -io-> ACTOR", "FLOW -io-> FUNC", "FLOW -io-> UC", "FLOW -relation-> SCHEMA", "FUNC -allocate-> MOD", "FUNC -compose-> FUNC [0..*]", "FUNC -io-> FLOW", "FUNC -satisfy-> REQ", "MOD -compose-> MOD [0..*]", "MOD -io-> MOD", "MOD -satisfy-> REQ", "MS -compose-> FUNC", "MS -compose-> MS", "MS -compose-> REQ", "MS -compose-> UC", "MS -relation-> MS", "REQ -compose-> REQ [0..*]", "SESSION -produces-> * (audit)", "SYS -compose-> MOD [0..*]", "SYS -compose-> REQ [0..*]", "SYS -compose-> SYS [0..*]", "SYS -compose-> UC [1..*]", "SYS -satisfy-> REQ", "TEST -verify-> REQ", "UC -compose-> FCHAIN [1..*]", "UC -compose-> REQ [1..*]"];
18
+ readonly elementTypes: readonly ["ACTOR", "CR", "FCHAIN", "FLOW", "FUNC", "MOD", "MS", "REQ", "SCHEMA", "SYS", "TEST", "UC"];
19
+ readonly traceTypes: readonly ["allocate", "compose", "io", "relation", "satisfy", "verify"];
20
+ readonly patterns: readonly ["ACTOR -io-> FLOW", "CR -relation-> FUNC", "CR -relation-> MOD", "CR -relation-> MS", "CR -relation-> REQ", "CR -relation-> UC", "FCHAIN -compose-> FUNC [1..*]", "FCHAIN -satisfy-> REQ", "FLOW -io-> ACTOR", "FLOW -io-> FUNC", "FLOW -relation-> SCHEMA [1]", "FUNC -allocate-> MOD [0..1]", "FUNC -compose-> FUNC [0..*]", "FUNC -io-> FLOW", "FUNC -satisfy-> REQ where target.kinds in {functional,postcondition,precondition}", "MOD -compose-> MOD [0..*]", "MOD -satisfy-> REQ where target.kinds in {mitigation,non-functional,risk}", "MS -compose-> FUNC", "MS -compose-> REQ", "MS -compose-> UC", "MS -relation-> MS label=depends-on", "REQ -compose-> REQ [0..*]", "SYS -compose-> MOD [0..*]", "SYS -compose-> REQ [0..*]", "SYS -compose-> SYS [0..*]", "SYS -compose-> UC [1..*]", "SYS -satisfy-> REQ where target.kinds in {mitigation,non-functional,risk}", "TEST -verify-> REQ", "UC -compose-> FCHAIN [1..*]", "UC -compose-> REQ [1..*]"];
21
+ readonly elementColumns: readonly ["OntologyElement.attributes", "OntologyElement.created_at", "OntologyElement.description", "OntologyElement.id", "OntologyElement.kinds", "OntologyElement.method", "OntologyElement.name", "OntologyElement.status", "OntologyElement.type", "OntologyElement.updated_at", "Trace.attributes", "Trace.created_at", "Trace.label", "Trace.source", "Trace.target", "Trace.type", "Trace.verified_at", "Trace.weight"];
21
22
  readonly attributes: readonly ["CR.rationale: string", "CR.spike: boolean", "CR.status: enum", "FLOW.protocol: string", "FLOW.qos: string", "FUNC.concept: boolean", "FUNC.external: boolean", "FUNC.measuredMs: number", "FUNC.realRef: object", "FUNC.safety_relevant: boolean", "FUNC.sourceFile: string", "FUNC.timingBudgetMs: number", "MOD.concept: boolean", "MOD.external: boolean", "MOD.kind: string", "MOD.path: string", "MOD.realRef: object", "REQ.detection: number", "REQ.occurrence: number", "REQ.severity: number", "SCHEMA.concept: boolean", "SCHEMA.contract: string", "SCHEMA.external: boolean", "SCHEMA.realRef: object", "TEST.concept: boolean", "TEST.sourceFile: string", "TEST.testRefs: array", "UC.operatingMode: string"];
22
- readonly rules: readonly ["AF-01 (warning) domain=[graph]", "AF-02 (warning) domain=[graph]", "AF-03 (warning) domain=[graph]", "AF-04 (warning) domain=[graph]", "AF-05 (warning) domain=[graph]", "AO-D01 (info) domain=[FUNC]", "AO-D03 (info) domain=[FUNC]", "BQ-01 (warning) domain=[REQ]", "BQ-02 (warning) domain=[REQ]", "BQ-04 (warning) domain=[REQ]", "BQ-06 (warning) domain=[REQ]", "BQ-07 (warning) domain=[REQ]", "CA-01 (error) domain=[FUNC]", "CL-01 (warning) domain=[ACTOR]", "CR-01 (warning) domain=[MOD]", "CR-R01 (error) domain=[CR]", "CR-R02 (error) domain=[CR]", "CR-R03 (warning) domain=[all]", "CR-R04 (warning) domain=[CR]", "FC-01 (warning) domain=[FCHAIN]", "FC-02 (warning) domain=[UC]", "FC-03 (warning) domain=[FUNC]", "FC-04 (warning) domain=[FCHAIN]", "FM-01 (warning) domain=[REQ]", "FM-02 (warning) domain=[REQ]", "FM-03 (error) domain=[REQ]", "IO-01 (warning) domain=[FUNC]", "MS-01 (warning) domain=[MS]", "MS-02 (error) domain=[MS]", "MS-03 (info) domain=[CR]", "MT-01 (warning) domain=[MOD]", "MT-02 (info) domain=[MOD]", "ND-01 (error) domain=[FUNC]", "ND-02 (error) domain=[SCHEMA]", "NFR-01 (warning) domain=[FCHAIN,FUNC,MOD]", "PH-01 (info) domain=[MOD]", "R-01 (error) domain=[REQ]", "R-02 (warning) domain=[FUNC]", "R-03 (error) domain=[MOD]", "R-04 (warning) domain=[MOD]", "R-05 (warning) domain=[TEST]", "R-08 (error) domain=[all]", "R-10 (warning) domain=[FLOW]", "R-12 (warning) domain=[FUNC]", "R-14 (warning) domain=[UC]", "R-15 (warning) domain=[FCHAIN]", "R-16 (warning) domain=[ACTOR]", "R-17 (warning) domain=[SYS]", "R-18 (error) domain=[all]", "R-19 (warning) domain=[TEST]", "R-20 (warning) domain=[FUNC]", "R-21 (warning) domain=[FCHAIN]", "R-22 (warning) domain=[FUNC]", "R-23 (warning) domain=[MOD]", "R-26 (warning) domain=[SCHEMA]", "R-27 (warning) domain=[MOD]", "R-29 (error) domain=[TEST]", "R-30 (warning) domain=[FUNC]", "R-31 (warning) domain=[FUNC]", "RD-01 (warning) domain=[REQ]", "RD-02 (warning) domain=[REQ]", "RD-03 (info) domain=[REQ]", "RD-04 (warning) domain=[FUNC,MOD,SYS]", "RT-01 (error) domain=[FUNC]", "SC-02 (warning) domain=[SCHEMA]", "SC-04 (warning) domain=[FLOW]", "UC-01 (error) domain=[UC]", "UC-02 (error) domain=[UC]", "UC-03 (warning) domain=[UC]", "UC-04 (warning) domain=[UC]", "UC-05 (info) domain=[UC]", "UC-06 (info) domain=[UC]", "VR-01 (info) domain=[TEST]"];
23
+ readonly rules: readonly ["AF-01 (warning) domain=[graph]", "AF-02 (warning) domain=[graph]", "AF-03 (warning) domain=[graph]", "AF-04 (warning) domain=[graph]", "AF-05 (warning) domain=[graph]", "BQ-01 (warning) domain=[REQ]", "BQ-02 (warning) domain=[REQ]", "BQ-04 (warning) domain=[REQ]", "BQ-06 (warning) domain=[REQ]", "BQ-07 (warning) domain=[REQ]", "BW-02 (warning) domain=[FUNC]", "CL-01 (warning) domain=[ACTOR]", "CR-01 (warning) domain=[MOD]", "CR-R01 (error) domain=[CR]", "CR-R02 (error) domain=[CR]", "CR-R03 (warning) domain=[all]", "FC-02 (warning) domain=[UC]", "FC-03 (warning) domain=[FUNC]", "FC-04 (warning) domain=[FCHAIN]", "FM-01 (warning) domain=[REQ]", "FM-02 (warning) domain=[REQ]", "FM-03 (error) domain=[REQ]", "IO-01 (warning) domain=[FUNC]", "MS-01 (warning) domain=[MS]", "MS-02 (error) domain=[MS]", "MS-03 (info) domain=[CR]", "MT-01 (warning) domain=[MOD]", "MT-02 (info) domain=[MOD]", "ND-01 (error) domain=[FUNC]", "ND-02 (error) domain=[SCHEMA]", "NFR-01 (warning) domain=[FCHAIN,FUNC,MOD]", "R-01 (error) domain=[REQ]", "R-02 (warning) domain=[FUNC]", "R-04 (warning) domain=[MOD]", "R-05 (warning) domain=[TEST]", "R-08 (error) domain=[all]", "R-10 (warning) domain=[FLOW]", "R-12 (warning) domain=[FUNC]", "R-15 (warning) domain=[FCHAIN]", "R-16 (warning) domain=[ACTOR]", "R-17 (warning) domain=[SYS]", "R-18 (error) domain=[all]", "R-19 (warning) domain=[TEST]", "R-20 (warning) domain=[FUNC]", "R-21 (warning) domain=[FCHAIN]", "R-22 (warning) domain=[FUNC]", "R-23 (warning) domain=[MOD]", "R-26 (warning) domain=[SCHEMA]", "R-29 (error) domain=[TEST]", "R-30 (warning) domain=[FUNC]", "R-31 (warning) domain=[FUNC]", "RD-01 (warning) domain=[REQ]", "RD-02 (warning) domain=[REQ]", "RD-03 (info) domain=[REQ]", "RD-04 (warning) domain=[FUNC,MOD,SYS]", "SC-02 (warning) domain=[SCHEMA]", "UC-01 (error) domain=[UC]", "UC-02 (error) domain=[UC]", "UC-03 (warning) domain=[UC]", "UC-04 (warning) domain=[UC]", "UC-05 (info) domain=[UC]", "UC-06 (info) domain=[UC]", "VR-01 (info) domain=[TEST]"];
23
24
  readonly conformanceRules: readonly ["RC-01 (error)", "RC-02 (error)", "RC-03 (error)", "RC-04 (warning)", "RC-05 (warning)", "RC-06 (warning)"];
25
+ readonly policy: readonly ["apTable = null", "boundaryWidth = {warning:5}", "crossingFlows = {warning:3}", "decompositionBreadth = {warning:9}", "instability = null", "lcom4 = {info:4,warning:6}", "moduleSize = {coupled:7,crossings:2,large:9}", "riskRpn = 100"];
26
+ readonly exports: readonly ["AF_RULES", "ALL_RULE_DEFS", "AO_RULES", "ActionPriority", "AnalysisArtifactId", "AnalysisFreshnessStampSchema", "ApTableSchema", "BOUNDED_PATTERNS", "BQ_RULES", "CODE_CONFORMANCE_RULES", "CR_RULES", "CodeFactsSchema", "DEFAULT_METRIC_POLICY", "DIMENSION_READINESS_DELTA_NAME", "DIMENSION_READINESS_NAME", "ELEMENT_ATTRIBUTES", "ELEMENT_DESCRIPTIONS", "ElementType", "ElementUid", "FC_RULES", "FM_RULES", "FileFactsSchema", "ImportEdgeSchema", "MAX_SLUG_LENGTH", "META_MODEL_VERSION", "MODELING_ELEMENT_TYPES", "MT_RULES", "MetricPolicySchema", "ND_RULES", "ONTOLOGY_VERSION", "OntologyElement", "OntologyGraph", "PHASE_READINESS_NAME", "PhaseGate", "REQUIRED_PATTERNS", "RULES_VERSION", "RULE_TO_DIMENSION", "RULE_TO_PHASE", "ReadinessDimension", "ReadinessReport", "ReadinessScore", "RealRefSchema", "RepoRelativePathSchema", "ReqKind", "RuleSeverity", "RuleViolation", "SC_RULES", "TRACE_PATTERNS", "TestRefSchema", "TestRefsSchema", "TestResult", "Trace", "TraceType", "UC_RULES", "V3_RULES", "VIEW_RULES", "VerificationMethod", "ViolationCandidate", "ViolationContext", "actionPriority", "allocationCohesion", "apMethod", "attributeTypeOf", "bq01Unambiguous", "bq02Verifiable", "bq04Necessary", "bq06Conforming", "bq07Complete", "bw02WhiteboxWidth", "cl01ConopsCompleteness", "cr01CrossingFlowCount", "decomposedFuncs", "evaluateAFRules", "evaluateAORules", "evaluateAllRules", "evaluateBQRules", "evaluateCRRules", "evaluateConformanceRules", "evaluateFCRules", "evaluateFMRules", "evaluateMTRules", "evaluateNDRules", "evaluateRules", "evaluateSCRules", "evaluateUCRules", "evaluateViewRules", "extractFormatE", "fc02LeafUcHasFchain", "fc03FchainFlat", "fc04ActorBounded", "fm01MissingFmeaAttributes", "fm02MissingMitigation", "fm03HighRiskUnverified", "funcSimilarity", "getRuleDefsForProfile", "hydrateAttrValue", "importCoverage", "indexOf", "io01CrossModuleCompleteness", "isElementUid", "isValidTrace", "jaccard", "maxOccurs", "minOccurs", "moduleMetrics", "mt01Instability", "mt02Lcom4", "nd01FuncNearDuplicate", "nd02SchemaNearDuplicate", "nfr01BudgetOvershoot", "normalizeReqKinds", "pairsAbove", "parseElementUid", "parseFormatE", "sc02IsReferenced", "schemaSimilarity", "serializeToFormatE", "setBQ04SimilarityMatrix", "toElementUid", "toEvaluableGraph", "tokens", "traceRejection", "tryParseElementUid", "uc01HasRequirements", "uc02HasActor", "uc03HasScenario", "uc04GoalDefined", "uc05HasPostcondition", "uc06HasPrecondition", "vr01TestNoResult"];
24
27
  };