@sigloch/contracts 3.3.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.
Files changed (42) hide show
  1. package/dist/harness/index.d.ts +2 -2
  2. package/dist/se/action-priority.d.ts +101 -0
  3. package/dist/se/action-priority.js +124 -0
  4. package/dist/se/analysis-freshness-rules.d.ts +5 -0
  5. package/dist/se/analysis-freshness-rules.js +5 -5
  6. package/dist/se/ao-rules.d.ts +5 -39
  7. package/dist/se/ao-rules.js +20 -13
  8. package/dist/se/conformance-rules.d.ts +2 -2
  9. package/dist/se/conformance-rules.js +36 -30
  10. package/dist/se/cr-quality-rules.d.ts +2 -1
  11. package/dist/se/cr-quality-rules.js +9 -7
  12. package/dist/se/evaluate-all.d.ts +18 -3
  13. package/dist/se/evaluate-all.js +29 -26
  14. package/dist/se/fchain-quality-rules.d.ts +2 -1
  15. package/dist/se/fchain-quality-rules.js +8 -6
  16. package/dist/se/fmea-rules.d.ts +3 -11
  17. package/dist/se/fmea-rules.js +53 -16
  18. package/dist/se/format-e-parser.d.ts +14 -1
  19. package/dist/se/format-e-parser.js +8 -3
  20. package/dist/se/index.d.ts +4 -2
  21. package/dist/se/index.js +4 -2
  22. package/dist/se/metric-rules.d.ts +13 -5
  23. package/dist/se/metric-rules.js +23 -13
  24. package/dist/se/near-duplicate-rules.d.ts +2 -0
  25. package/dist/se/near-duplicate-rules.js +2 -2
  26. package/dist/se/ontology.d.ts +55 -4
  27. package/dist/se/ontology.js +46 -6
  28. package/dist/se/policy.d.ts +65 -0
  29. package/dist/se/policy.js +100 -0
  30. package/dist/se/quality-rules.d.ts +2 -1
  31. package/dist/se/quality-rules.js +9 -7
  32. package/dist/se/readiness.d.ts +9 -1
  33. package/dist/se/readiness.js +18 -2
  34. package/dist/se/rules.d.ts +25 -5
  35. package/dist/se/rules.js +112 -47
  36. package/dist/se/schema-quality-rules.d.ts +2 -1
  37. package/dist/se/schema-quality-rules.js +6 -4
  38. package/dist/se/uc-quality-rules.d.ts +2 -1
  39. package/dist/se/uc-quality-rules.js +10 -8
  40. package/dist/se/view-rules.d.ts +2 -6
  41. package/dist/se/view-rules.js +40 -13
  42. package/package.json +2 -1
@@ -58,25 +58,65 @@ export const RepoRelativePathSchema = z
58
58
  * Runnable binding for a TEST element (CR-GC-134, ontology bump 3.4.0).
59
59
  * Resolves a TEST node to the concrete artefact a runner can execute, enabling
60
60
  * bottom-up selective test deduction (`graph_tests`): change → impacted TESTs →
61
- * `testRef` → minimal selective run command.
61
+ * `testRefs` → minimal selective run command.
62
62
  * - `file` : test file path, e.g. `tests/foo.test.ts` (the runner target).
63
63
  * - `case` : optional named case/`describe`/`it` block within the file.
64
64
  * - `tool` : the runner, e.g. `vitest`, `playwright`, `pytest`.
65
65
  * - `level` : optional level, e.g. `unit`, `integration`, `validation`.
66
- * Stored under `OntologyElement.attributes.testRef` (additive, opt-in validation).
66
+ *
67
+ * `tool` steht bewusst **pro Eintrag**, nicht hochgezogen: eine Abnahme mischt real die
68
+ * Runner — ein TEST kann aus `tests/dashboard.test.mjs` (vitest) *und*
69
+ * `tests/visual/dashboard-render.spec.mjs` (playwright) bestehen. Ein Runner je TEST-Knoten
70
+ * wäre eine Lüge, die das alte 1:1-Schema nur deshalb nicht produzierte, weil es die zweite
71
+ * Datei gar nicht erst zuliess.
67
72
  */
68
73
  export const TestRefSchema = z.object({
69
74
  file: RepoRelativePathSchema,
70
75
  case: z.string().optional(),
71
76
  tool: z.string(),
72
77
  level: z.string().optional(),
78
+ /**
79
+ * CR-SM-231b: das Ergebnis haengt **pro Eintrag**, aus demselben Grund wie `tool`.
80
+ *
81
+ * Vorher lag `testResult` am TEST-**Knoten**. Mit n Eintraegen ist das mehrdeutig: laeuft eine
82
+ * Abnahme als vitest *und* playwright, kann ein einzelnes Ergebnis nicht sagen, welcher Lauf
83
+ * gemeint ist — und „einer rot, einer gruen" ist gar nicht darstellbar. Genau der Zustand,
84
+ * den ein Gate wissen muss.
85
+ *
86
+ * Optional: ein Eintrag ohne Ergebnis ist noch nicht gelaufen, nicht „bestanden". VR-01
87
+ * meldet das.
88
+ */
89
+ result: TestResult.optional(),
90
+ /** ISO-Zeitstempel des Laufs, der `result` erzeugt hat. Ohne ihn ist ein Ergebnis undatiert. */
91
+ ranAt: z.iso.datetime().optional(),
92
+ /** Repo-relativer Pfad zum Lauf-Artefakt (Report, Screenshot, Trace) — die Evidenz zur Aussage. */
93
+ evidence: RepoRelativePathSchema.optional(),
73
94
  });
95
+ /**
96
+ * CR-SM-231: eine Abnahme, **n** Testdateien — 1:n, nie n:m.
97
+ *
98
+ * Vorher war `testRef` ein einzelnes Objekt: ein TEST-Knoten war an genau eine Datei bindbar.
99
+ * Eine Abnahme aus Unit- *und* Visual-Lauf konnte ihre Evidenz damit nicht vollstaendig
100
+ * deklarieren, und der Ausweichweg war belegt — dieselbe Spec-Datei stand im `testRef` zweier
101
+ * TEST-Knoten. Damit war die Relation faktisch n:m: ein roter Lauf war keiner Abnahme mehr
102
+ * eindeutig zuordenbar, waehrend der TRR-Gate dieselbe Evidenz doppelt zaehlte.
103
+ *
104
+ * **Warum n:m hier falsch ist.** n:m zwischen Abnahme und Anforderung ist bereits korrekt
105
+ * modelliert und in Gebrauch (`TEST -[verify]-> REQ`) — dafuer ist eine Kante da. Die Bindung
106
+ * an die Laufdatei ist etwas anderes: sie ist **Evidenz-Adresse**, kein Traceability-Link. Sie
107
+ * gehoert ins Attribut und bleibt 1:n — ein TEST kennt n Dateien, eine Datei gehoert zu
108
+ * hoechstens einem TEST. Die zweite Haelfte erzwingt R-29.
109
+ *
110
+ * Gespeichert unter `OntologyElement.attributes.testRefs`. Das alte `testRef` entfaellt
111
+ * ersatzlos — kein Union, kein Alias, keine parallelen Pfade.
112
+ */
113
+ export const TestRefsSchema = z.array(TestRefSchema).min(1);
74
114
  /**
75
115
  * Realization binding for an element (CR-228, ontology bump 3.9.0) — unifies the
76
116
  * byte-identical former `codeRef` (FUNC → code symbol) and `schemaRef` (SCHEMA →
77
117
  * Zod export), and extends to MOD (physical part → CAD/geometry artefact). The
78
118
  * *type* of the pointing element disambiguates what kind of realization it is:
79
- * FUNC→code, SCHEMA→Zod-def, physical MOD→CAD. TEST keeps its own `testRef`
119
+ * FUNC→code, SCHEMA→Zod-def, physical MOD→CAD. TEST keeps its own `testRefs`
80
120
  * (a TEST is not just located but *executed* — the runner is the extra value).
81
121
  * - `file` : realization file path, e.g. `src/harness.ts`, `part.step`.
82
122
  * - `symbol` : the realizing symbol (function/class/Zod export). Optional — a
@@ -181,10 +221,10 @@ export const MODELING_ELEMENT_TYPES = ElementType.options.filter(t => t !== 'SES
181
221
  */
182
222
  export const ELEMENT_ATTRIBUTES = {
183
223
  TEST: [
184
- { key: 'testResult', type: 'enum', enumValues: TestResult.options, description: 'Test execution outcome' },
224
+ // CR-SM-231b: das knotenweite `testResult` ist weg das Ergebnis haengt pro testRefs-Eintrag.
185
225
  { key: 'sourceFile', type: 'string', description: 'Test file path (e.g. tests/foo.test.ts)' },
186
- { key: 'testRef', type: 'object', description: 'Runnable binding {file, case?, tool, level?} — see TestRefSchema (CR-GC-134)' },
187
- { key: 'concept', type: 'boolean', description: 'Concept-only TEST: no run artifact yet; exempt from the R-19 testRef-binding requirement (CR-GC-205)' },
226
+ { key: 'testRefs', type: 'array', description: 'Runnable bindings [{file, case?, tool, level?, result?, ranAt?, evidence?}, …] one acceptance, n test files (1:n), each with its own outcome. See TestRefsSchema (CR-SM-231)' },
227
+ { key: 'concept', type: 'boolean', description: 'Concept-only TEST: no run artifact yet; exempt from the R-19 testRefs-binding requirement (CR-GC-205)' },
188
228
  ],
189
229
  REQ: [
190
230
  { key: 'severity', type: 'number', description: 'FMEA severity (1-10)' },
@@ -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[];
@@ -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
- export function evaluateBQRules(graph) {
205
- return BQ_RULES.flatMap(rule => rule.evaluate(graph));
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
  }
@@ -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>;
@@ -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
- ready: z.boolean(), // score >= 0.7
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',
@@ -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
- evaluate: (graph: OntologyGraph) => RuleViolation[];
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[];