@sigloch/contracts 10.13.0 → 11.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 (37) hide show
  1. package/dist/se/analysis-freshness-rules.d.ts +49 -15
  2. package/dist/se/analysis-freshness-rules.js +109 -34
  3. package/dist/se/ao-rules.js +3 -3
  4. package/dist/se/conformance-rules.d.ts +4 -0
  5. package/dist/se/conformance-rules.js +37 -32
  6. package/dist/se/cr-quality-rules.js +4 -76
  7. package/dist/se/evaluate-all.d.ts +5 -0
  8. package/dist/se/evaluate-all.js +2 -1
  9. package/dist/se/fchain-quality-rules.js +4 -4
  10. package/dist/se/fmea-rules.js +4 -4
  11. package/dist/se/format-e-parser.js +1 -1
  12. package/dist/se/grammar-snapshot.d.ts +6 -6
  13. package/dist/se/grammar-snapshot.js +91 -90
  14. package/dist/se/index.d.ts +3 -2
  15. package/dist/se/index.js +4 -2
  16. package/dist/se/metric-rules.d.ts +3 -0
  17. package/dist/se/metric-rules.js +3 -3
  18. package/dist/se/near-duplicate-rules.d.ts +2 -0
  19. package/dist/se/near-duplicate-rules.js +2 -2
  20. package/dist/se/ontology.d.ts +23 -4
  21. package/dist/se/ontology.js +37 -14
  22. package/dist/se/placeholder.d.ts +1 -0
  23. package/dist/se/placeholder.js +13 -0
  24. package/dist/se/quality-rules.js +8 -8
  25. package/dist/se/readiness.d.ts +45 -47
  26. package/dist/se/readiness.js +57 -120
  27. package/dist/se/rule-due.d.ts +35 -0
  28. package/dist/se/rule-due.js +83 -0
  29. package/dist/se/rule-help.d.ts +19 -3
  30. package/dist/se/rule-help.js +97 -26
  31. package/dist/se/rules.d.ts +18 -0
  32. package/dist/se/rules.js +119 -73
  33. package/dist/se/schema-quality-rules.d.ts +1 -1
  34. package/dist/se/schema-quality-rules.js +1 -1
  35. package/dist/se/uc-quality-rules.js +6 -6
  36. package/dist/se/view-rules.js +6 -4
  37. package/package.json +1 -1
@@ -31,8 +31,11 @@
31
31
  * umformulierter Satz darf keinen Major ausloesen, deshalb steht im Golden-File nur die
32
32
  * Schluesselmenge, nicht die Prosa.
33
33
  *
34
- * Sprache: Englisch, wie die Regelbeschreibungen selbst. 18,6 KB reine Strings — der
35
- * `./browser`-Eintrag bleibt transitiv `node:`-frei (CR-SM-230), Strings ziehen nichts nach.
34
+ * Sprache: Englisch, wie die Regelbeschreibungen selbst — ausser `vorschlag`, der Satz, den ein Nutzer
35
+ * seinem Agenten schickt (CR-SM-384): Deutsch, weil er in der Sprache des Nutzers steht, nicht in der
36
+ * des Katalogs. Bis CR-SM-384 lag er als `VORSCHLAG_REGEL` in graphcode, ein paralleler Pfad zu
37
+ * `plain` und `fix_hint` mit derselben Driftgefahr wie oben. Reine Strings — der `./browser`-Eintrag
38
+ * bleibt transitiv `node:`-frei (CR-SM-230), Strings ziehen nichts nach.
36
39
  *
37
40
  * @author andreas@siglochconsulting
38
41
  */
@@ -62,8 +65,8 @@ export const RULE_HELP = {
62
65
  prompt: "se-fmea",
63
66
  },
64
67
  'AF-05': {
65
- plain: "No implementation plan is on record → derive the build order.",
66
- se: "No `analysisFreshness.implplan` stamp under `SYS.attributes`.",
68
+ plain: "Parts of the model are not built yet and nobody has ordered the work → derive the build order.",
69
+ se: "Unbuilt elements exist (`TEST` / `FUNC` / `SCHEMA` without a binding, the exemptions of R-19/R-20/R-26 apply) and no `CR` has `status: open`. The plan is the set of open CRs, not a stamp; it falls due again with every change (CR-SM-395).",
67
70
  prompt: "se-plan",
68
71
  },
69
72
  'BQ-01': {
@@ -93,80 +96,92 @@ export const RULE_HELP = {
93
96
  'BW-02': {
94
97
  plain: "This block hands out many different kinds of data at its edge → whoever uses it has to understand all of them, so either bundle them or split the block.",
95
98
  se: "Whitebox boundary width: distinct `SCHEMA` contracts on `FUNC` `io` `FLOW` `io` `FUNC` paths with one endpoint inside the `compose` subtree and one outside, judged against `metricPolicy.boundaryWidth.warning`. Parnas, information hiding — what a boundary HIDES is what makes it worth having. Rolled up over the subtree because a decomposed `FUNC` carries no `io` edges of its own (CR-SM-283).",
99
+ vorschlag: 'Bündle die Datenformate an der Grenze von {n} oder teile den Block.',
96
100
  },
97
101
  'CL-01': {
98
102
  plain: "Someone only ever uses the system in one way, which usually means their other situations are missing → describe the scenarios you left out.",
99
103
  se: "`ACTOR` whose `UC`s cover fewer than 2 distinct `operatingMode`s — a ConOps completeness signal.",
100
104
  prompt: "se-conops",
105
+ vorschlag: 'Ordne den Akteuren {n} Abläufe in mindestens zwei Betriebsarten zu.',
101
106
  },
102
107
  'CR-01': {
103
108
  plain: "Two parts exchange an unusually large amount of data, which usually means the boundary is in the wrong place → reconsider the cut.",
104
109
  se: "High crossing `io` FLOW count between two `MOD`s — a coupling metric, advisory.",
110
+ vorschlag: 'Prüfe den Schnitt zwischen {n}, dort fließen ungewöhnlich viele Daten.',
105
111
  },
106
112
  'CR-R01': {
107
113
  plain: "A change is recorded but says nothing about what it changes → link it to what it touches.",
108
114
  se: "`CR` with no `relation` traces. It tracks nothing, so it is not traceable evidence.",
115
+ vorschlag: 'Verbinde die Änderungsaufträge {n} mit dem, was sie ändern.',
109
116
  },
110
117
  'CR-R02': {
111
118
  plain: "A change is marked finished but there is no commit proving it → record the commit, or set it back to open.",
112
119
  se: "`CR` with `status:done` and no `commitRef` attribute. This is the graph-vs-reality check for change history: \"done\" without evidence.",
120
+ vorschlag: 'Trage bei den erledigten Änderungsaufträgen {n} den Commit nach.',
113
121
  },
114
122
  'CR-R03': {
115
123
  plain: "Several open changes touch the same thing, so they will collide → sequence them or merge them.",
116
124
  se: "One element tracked by more than one `CR` with `status` open/in-progress.",
117
- },
118
- 'CR-R05': {
119
- plain: "This smallest-piece requirement has no work order — no change request points at it or at the function that fulfils it, and that function is not built yet, so no plan will ever build it → attach it to the change request that builds it.",
120
- se: "Leaf `REQ` (no `compose`→`REQ` children) with no build order: no `CR -relation->` on the REQ itself nor on a `FUNC` that `satisfy`s it (CR-SM-343; the REQ side of CR-R01). A `FUNC` that is already built — valid `realRef` or `external`, not `concept` — covers the REQ without a CR (CR-SM-375). A CR on a `MOD`/`SYS` carrier does not count — a module is a container; such REQs take a direct `CR -relation-> REQ`. Silent, and not scored, on a graph without any `CR` node (`RULE_PRECONDITION`).",
121
- prompt: "se-plan",
125
+ vorschlag: 'Kläre, welcher der offenen Änderungsaufträge an {n} zuerst ändert.',
122
126
  },
123
127
  'FC-02': {
124
128
  plain: "A scenario that is not broken into sub-scenarios has no described sequence of steps → add one, even if the steps are done by hand.",
125
129
  se: "Leaf `UC` (no `UC -compose-> UC`) with no `FCHAIN`. A chain may consist of EXISTING FUNCs an actor strings together — it costs a node plus compose edges, not code.",
126
130
  prompt: "se:author-uc",
131
+ vorschlag: 'Beschreibe die Abläufe {n} als Kette von Funktionen.',
127
132
  },
128
133
  'FC-03': {
129
134
  plain: "A step inside a sequence contains further steps, so the sequence has hidden depth → lift them to the same level.",
130
135
  se: "`FUNC` inside an `FCHAIN` that itself `compose`s other `FUNC`s. Chains are flat by construction.",
136
+ vorschlag: 'Hebe die inneren Schritte der Funktionen {n} auf die Ebene ihrer Kette.',
131
137
  },
132
138
  'FC-04': {
133
139
  plain: "A sequence either has nobody starting it or nothing coming back out → wire both ends to whoever uses it.",
134
140
  se: "`FCHAIN` lacking an entry (`ACTOR -io-> FLOW -io-> FUNC∈chain`) or an exit (`FUNC∈chain -io-> FLOW -io-> ACTOR`). Stricter than FC-01: both directions, at FUNC/FLOW level, no UC-level bypass.",
141
+ vorschlag: 'Verbinde Anfang und Ende der Funktionsketten {n} mit dem Nutzer.',
135
142
  },
136
143
  'FC-05': {
137
144
  plain: "The steps of this sequence do not hand their results to each other — it falls apart into pieces, so nobody can say how long it is or where it gets stuck → add the missing step, connect the pieces with a data flow, or split it into separate sequences.",
138
145
  se: "`FCHAIN` whose member `FUNC`s do not form one (weakly) connected component along producer → consumer (`FUNC -io-> FLOW -io-> FUNC`, both ends members). Per side component the cause: `missing-link` (main and side part are joined through a `FUNC` outside the chain — compose it) or `bag` (no FUNC joins them: a missing FLOW between members, or parallel services at a shared source — split). One finding per chain, components in `context.side_components` (CR-SM-242). Silent while any member lacks an io input or output (R-31 first); entry/exit belong to FC-04 (CR-SM-363).",
146
+ vorschlag: 'Verbinde die Schritte der Funktionsketten {n} über Datenflüsse.',
139
147
  },
140
148
  'FM-01': {
141
149
  plain: "A requirement is marked as a risk but carries no risk ratings → rate how bad, how likely and how detectable it is (1-10 each).",
142
150
  se: "`REQ` with `role:\"risk\"` missing `severity` / `occurrence` / `detection` attributes (AIAG-VDA). The role is the requirement's motivation, not its kind — satisfy-neutral (CR-SM-365).",
143
151
  prompt: "se-fmea",
152
+ vorschlag: 'Bewerte die Risiken {n} nach Schwere, Auftreten und Entdeckung.',
144
153
  },
145
154
  'FM-02': {
146
155
  plain: "A known risk has nothing planned against it → write the countermeasure as its own requirement.",
147
156
  se: "`REQ` with `role:\"risk\"` and no `compose`d `REQ` with `role:\"mitigation\"`. The mitigation keeps its own kind (functional or non-functional) and is satisfied like any REQ of that kind (CR-SM-365).",
148
157
  prompt: "se-fmea",
158
+ vorschlag: 'Gib den Risiken {n} eine Gegenmaßnahme.',
149
159
  },
150
160
  'FM-03': {
151
161
  plain: "A high risk has no test that actually passed → add a test proving the countermeasure works.",
152
162
  se: "`REQ` with `role:\"risk\"`, Action Priority High (AIAG-VDA, RPN band as interim) and no verifying `TEST` whose every `testRefs` entry has `result:\"passed\"`.",
153
163
  prompt: "se-fmea",
164
+ vorschlag: 'Gib den hohen Risiken {n} einen Test.',
154
165
  },
155
166
  'IO-01': {
156
167
  plain: "Two steps in the same sequence have no described data passing between them → add the data one hands to the other.",
157
168
  se: "A `FUNC` pair inside one `FCHAIN` with no `io` path (`FUNC -io-> FLOW -io-> FUNC`) connecting them.",
169
+ vorschlag: 'Ergänze den Datenfluss zwischen den Schritten {n}.',
158
170
  },
159
171
  'IO-02': {
160
172
  plain: "Two different places write into the same flow, so a reader cannot tell which version arrives \u2192 give each source its own flow; they may keep sharing one contract.",
161
173
  se: "`FLOW` with more than one producer (`FUNC`/`ACTOR -io-> FLOW`). R-10 checks the LOWER bound of the same axis (at least one producer, at least one consumer); the two can never fire on the same FLOW, so there is no double count. Only the producer side is bounded: several consumers are the normal shape of a shared contract \u2014 one source, many readers, which is exactly how a central configuration looks. One finding per FLOW, `value` = number of producers, `threshold` 1. Severity `error` (hygiene) and deliberately NOT in STEER_RULES — a decision, not a measured conflict: a split flow keeps its `SCHEMA`, so BW-02 (distinct contracts per boundary) does not rise. Whether a gate blocks a new finding is the consumer's gating choice, not part of the rule.",
174
+ vorschlag: 'Gib jeder Quelle der Datenflüsse {n} einen eigenen Datenfluss.',
162
175
  },
163
176
  'MS-01': {
164
177
  plain: "A milestone has no work assigned to it → assign the work items that belong to it.",
165
178
  se: "`MS` with no `CR` `relation`.",
179
+ vorschlag: 'Ordne den Meilensteinen {n} ihren Umfang zu.',
166
180
  },
167
181
  'MS-02': {
168
182
  plain: "A milestone waits on another milestone that doesn't exist → fix or remove the dependency.",
169
183
  se: "`MS` `depends-on` relation targeting a missing `MS`.",
184
+ vorschlag: 'Korrigiere die Abhängigkeiten der Meilensteine {n}.',
170
185
  },
171
186
  'MS-03': {
172
187
  plain: "A change is not assigned to any milestone, so it has no place in the plan → assign it.",
@@ -176,10 +191,12 @@ export const RULE_HELP = {
176
191
  'MT-01': {
177
192
  plain: "This module draws more from others than others draw from it → it will keep changing whenever they do. Measured, not judged: no threshold is set by default.",
178
193
  se: "Instability I = fan_out / (fan_in + fan_out), counted in DISTINCT CONTRACTS crossing the module boundary — the same `moduleCrossings` definition CR-01, R-04 and BW-02 use (CR-SM-274/276). CR-SM-293 fixed both halves: it used to count every trace touching the module, of which only 34 % was coupling (`allocate` is module SIZE, `satisfy` is specification); and the direction was inverted — the CONSUMER depends, so supplying outward is fan_in (Martin's Ca) and drawing inward is fan_out (Ce). `metricPolicy.instability` defaults to `null`: the distribution is bimodal, so no threshold can be read from it. The number stays in every `graph_metrics` module row, next to `uphillDependencies` (CR-SM-301).",
194
+ vorschlag: 'Prüfe die Abhängigkeiten des Moduls {n}.',
179
195
  },
180
196
  'MT-02': {
181
197
  plain: "The parts inside this module never talk to each other → it is really several modules in one.",
182
198
  se: "LCOM4 over the BOXES of this module whitebox: its sub-MODs (`MOD -compose-> MOD`) plus its directly allocated `FUNC`s. A box owns its whole subtree, so a decomposed block carries the contracts of its leaves — the same ownership chain R-04 (CR-SM-282), BW-02 (CR-SM-283) and R-23 (CR-SM-321) use; without it a container counted as an empty group of its own and the number grew with decomposition DEPTH (CR-SM-326). Connected means a shared CONTRACT (`FLOW -relation-> SCHEMA`, else the untyped flow) — the same counting base as CR-01/R-04/MT-01 since CR-SM-274/276, not FLOW identity. CR-SM-297 dropped `satisfy`: two FUNCs meeting the same requirement can be fully decoupled at runtime, and if they share one, the REQUIREMENT is what needs decomposing. `null` (no judgement) below two boxes and where no box carries a contract at all — an unwired FUNC is R-31's statement, at the element. `info` from `metricPolicy.lcom4.info`, `warning` from `.warning` (CR-GC-329).",
199
+ vorschlag: 'Teile das Modul {n}, seine Teile arbeiten nicht zusammen.',
183
200
  },
184
201
  'MT-04': {
185
202
  plain: "This block's parts never talk to each other → it is really two blocks that happen to sit under one name.",
@@ -188,194 +205,248 @@ export const RULE_HELP = {
188
205
  'ND-01': {
189
206
  plain: "Two functions look like the same function written twice → merge them, or make clear what each one does differently.",
190
207
  se: "Near-duplicate `FUNC` above 0.85 similarity (name, description and legal trace partners). Since CR-SM-286 the similarity is computed IN the rule, cached per graph — before that it had to be injected, and without injection the rule returned green, indistinguishable from \"no duplicates\".",
208
+ vorschlag: 'Führe die doppelten Funktionen {n} zusammen oder grenze sie ab.',
191
209
  },
192
210
  'ND-02': {
193
211
  plain: "Two data contracts describe the same thing twice → merge them, or say what distinguishes them.",
194
212
  se: "Near-duplicate `SCHEMA` above 0.85 similarity (name, description, fields and legal trace partners). Partners are filtered through `isValidTrace`: a rule must not reach its verdict via an edge R-18 rejects (CR-SM-286).",
213
+ vorschlag: 'Führe die doppelten Datenformate {n} zusammen oder grenze sie ab.',
195
214
  },
196
215
  'NFR-01': {
197
216
  plain: "Something measured exceeds the limit that was set for it → fix it or change the limit deliberately.",
198
217
  se: "Measured value above its declared budget on a `MOD` (physical) or `FUNC`/`FCHAIN` (behavioural).",
218
+ vorschlag: 'Bringe {n} unter sein Budget oder ändere das Budget bewusst.',
199
219
  },
200
220
  'R-01': {
201
221
  plain: "A feature you've promised has no test proving it's met, so you can't show it works → add or author a test for it.",
202
222
  se: "`REQ` with no incoming `verify` trace (test→requirement coverage, INCOSE V&V).",
203
223
  prompt: "se:close-violations",
224
+ vorschlag: 'Ergänze Tests für die Anforderungen {n}.',
204
225
  },
205
226
  'R-02': {
206
227
  plain: "A function isn't linked to any feature it's meant to build, so it may be dead code → link it to the feature it serves, or delete it.",
207
228
  se: "`FUNC` with no `satisfy` trace to a `REQ` (design→requirement traceability).",
229
+ vorschlag: 'Ordne die Funktionen {n} den Anforderungen zu, die sie erfüllen.',
208
230
  },
209
231
  'R-04': {
210
232
  plain: "Too many different data formats cross this module's boundary → merge formats, or move the functions that carry them.",
211
233
  se: "`MOD` whose boundary is crossed by `metricPolicy.boundaryWidth.warning` or more DISTINCT contracts (`SCHEMA` on the io path `FUNC` ─io→ `FLOW` ─io→ `FUNC` across the boundary, union over all neighbours — CR-SM-276). Same question and same threshold as BW-02 on the FUNC tree (CR-SM-312); module SIZE is RD-04's question since CR-SM-311.",
212
234
  prompt: "se-view:arch",
235
+ vorschlag: 'Verringere die Datenformate an der Grenze des Moduls {n}.',
213
236
  },
214
237
  'R-05': {
215
238
  plain: "A test doesn't check any feature you promised → link it to the feature it tests, or remove it.",
216
239
  se: "`TEST` with no `verify` trace at all — neither to a `REQ` (test→requirement coverage) nor to a `SCHEMA` (contract test, CR-SM-317).",
240
+ vorschlag: 'Ordne die Tests {n} den Anforderungen zu, die sie prüfen.',
217
241
  },
218
242
  'R-32': {
219
- plain: "A data contract exists in code but no test exercises it as a contract → add a test that tries every variant, including the ones it must reject, and link it to the schema.",
220
- se: "`SCHEMA` with a symbol `realRef` (a Zod contract) and no `TEST -verify-> SCHEMA`. RC-04 checks the parse at the boundary; this checks the contract test (CR-SM-319).",
243
+ plain: "A data format is defined but no test exercises it as a contract → add a test that tries every variant, including the ones it must reject, and link it to the schema.",
244
+ se: "`SCHEMA` with no `TEST -verify-> SCHEMA` — every SCHEMA, bound or not (CR-SM-396; until then only those with a symbol `realRef`). RC-04 checks the parse at the boundary; this checks the contract test (CR-SM-319).",
245
+ vorschlag: 'Gib den Datenformaten {n} einen Vertragstest.',
246
+ },
247
+ 'R-33': {
248
+ plain: "The model has no system yet — nothing says what is being built and where it ends → name the system.",
249
+ se: "No `SYS` element in the graph: the existence rule of stage 1. Everything else is composed below the system (CR-SM-395).",
250
+ vorschlag: 'Lege zuerst das System an und benenne, was gebaut wird.',
221
251
  },
222
252
  'R-08': {
223
253
  plain: "A link points at something that no longer exists → repair or remove the broken link.",
224
254
  se: "Trace whose source or target element is missing (dangling reference).",
255
+ vorschlag: 'Repariere oder entferne die Verbindungen an {n}, deren Ziel fehlt.',
225
256
  },
226
257
  'R-10': {
227
258
  plain: "A piece of data goes nowhere — nothing produces or consumes it → connect it to a function or a person/outside system.",
228
259
  se: "`FLOW` with no `io` trace to a `FUNC` or `ACTOR`.",
260
+ vorschlag: 'Vervollständige die Datenflüsse {n}: woher sie kommen und wohin sie gehen.',
229
261
  },
230
262
  'R-12': {
231
263
  plain: "Two items depend on each other in a loop, so neither can stand alone → remove or redirect one of the two links.",
232
264
  se: "Direct cycle: A→B and B→A via the same trace type, checked on `compose` / `allocate` / `relation` only. Data (`io`) is exempt — a function that reads and writes the same `FLOW` is normal reuse, not a dependency cycle.",
265
+ vorschlag: 'Löse die zyklische Abhängigkeit um {n} auf.',
233
266
  },
234
267
  'R-15': {
235
- plain: "A sequence of steps for a use case is empty → add the functions that make it up.",
236
- se: "`FCHAIN` with no `compose` to any `FUNC`.",
268
+ plain: "A sequence of steps is empty, or serves no use case → add the functions that make it up, and attach it to the use case it belongs to.",
269
+ se: "`FCHAIN` with no `compose` to any `FUNC`, or with no incoming `compose` from a `UC` — one rule_id, up to two findings per chain (pattern of R-10).",
270
+ vorschlag: 'Gib den Funktionsketten {n} ihre Funktionen und ordne sie ihrem Ablauf zu.',
237
271
  },
238
272
  'R-16': {
239
273
  plain: "A person or outside system isn't connected to anything → connect it to the data it sends or receives.",
240
274
  se: "`ACTOR` with no `io` trace to a `FLOW`.",
275
+ vorschlag: 'Verbinde den Nutzer {n} über Datenflüsse mit den Funktionen.',
241
276
  },
242
277
  'R-17': {
243
- plain: "The top level of your project is empty — nothing is inside it → add the main use cases, features, or modules.",
244
- se: "`SYS` with no `compose` to `UC` / `REQ` / `MOD`.",
278
+ plain: "Nothing says yet who uses the system for what → add the main use cases.",
279
+ se: "`SYS` with no `compose` to a `UC`: the existence rule of stage 2. Requirements or modules below the system do not stand in for a use case (CR-SM-396).",
280
+ vorschlag: 'Lege die Abläufe des Systems {n} an.',
245
281
  },
246
282
  'R-18': {
247
283
  plain: "You connected two items in a combination that isn't allowed → use an allowed link, or fix what's at each end.",
248
284
  se: "Trace whose (source-type, target-type) pair isn't an allowed combination in the metamodel of legal links.",
285
+ vorschlag: 'Korrigiere die unzulässigen Verbindungen an {n}.',
249
286
  },
250
287
  'R-19': {
251
- plain: "A test that's meant to run doesn't point to a test file → add the link to the test file, or, if it isn't written yet, mark it not-yet-written.",
252
- se: "Realized `TEST` with no valid `testRefs` `[{file, case?, tool}, …]` (at least one entry); else set `concept:true` (a stub).",
288
+ plain: "Building has started, and a test doesn't point to a test file yet → add the link to the test file.",
289
+ se: "`TEST` with no valid `testRefs` `[{file, case?, tool}, …]` (at least one entry)." +
290
+ " Stage 11: due only once the build is open — an open CR or a first `realRef`/`testRefs` in the graph; before that it is not evaluated, not passed (CR-SM-395).",
291
+ vorschlag: 'Verbinde die Tests {n} mit ihren Testdateien.',
253
292
  },
254
293
  'R-20': {
255
- plain: "A function is supposed to be built but doesn't point to its code → add the link to its code; or mark it not-built-yet / from-an-outside-library.",
256
- se: "Realized `FUNC` with no valid `realRef` `{file, symbol}` (graph↔code binding); else `concept:true` / `external:true`.",
294
+ plain: "Building has started, and a function doesn't point to its code yet → add the link to its code; or mark it as coming from an outside library.",
295
+ se: "`FUNC` with no valid `realRef` `{file, symbol}` (graph↔code binding); else `external:true`." +
296
+ " Stage 11: due only once the build is open — an open CR or a first `realRef`/`testRefs` in the graph; before that it is not evaluated, not passed (CR-SM-395).",
297
+ vorschlag: 'Verbinde die Funktionen {n} mit ihrem Code.',
257
298
  },
258
299
  'R-21': {
259
300
  plain: "Two functions hand data over, but they are not in one chain together — or they are, and the chain is not covered: some function in it has no requirement, and no end-to-end test checks the chain → give each function of the chain a requirement it fulfils, or give the chain an end-to-end quality requirement and a test for it.",
260
301
  se: "FUNC↔FUNC handover (`FUNC` ─io→ `FLOW` ─io→ `FUNC`), two findings. (a) endpoints share NO `FCHAIN` → finding at the PRODUCER: no integration scope is declared. (b) endpoints share one, but no shared chain is covered → finding at the chain, naming the member FUNCs without a REQ. A chain is covered either (1) through its members — EVERY member FUNC (`FCHAIN` ─compose→ `FUNC`) satisfies at least one `REQ`; verifying those REQs is R-01's job (CR-SM-376) — or (2) end-to-end — a verified integration test (`TEST` ─verify→ `REQ` ←satisfy─ `FCHAIN`); an `FCHAIN` satisfies only non-functional REQs (CR-SM-366). SILENT when either endpoint is in no chain at all (that is R-30's statement) and when either is infrastructure (`chains >= policy.criticality.infrastructure`): a handover into a function that runs through every chain is a bus, not a missing test.",
302
+ vorschlag: 'Bringe die Übergaben an {n} in eine Funktionskette, deren Funktionen Anforderungen erfüllen oder die ein Integrationstest prüft.',
261
303
  },
262
304
  'R-22': {
263
305
  plain: "A function isn't assigned to any building block, so it has no home in the structure → put it on a module.",
264
306
  se: "`FUNC` with no `allocate` trace to a `MOD` (deployment assignment); every function lives on exactly one module.",
307
+ vorschlag: 'Ordne die Funktionen {n} Modulen zu.',
265
308
  },
266
309
  'R-23': {
267
310
  plain: "A building block is empty — no function is assigned to it or to any block inside it → put a function on it, or remove the empty block.",
268
311
  se: "`MOD` with no `FUNC` ─allocate→ trace anywhere in its `compose` subtree (`subtreeFuncs`, the same count R-04 uses, CR-SM-321); the module-side complement of R-22 (empty-container signal like R-14/R-16/R-17). A container `MOD` whose sub-modules hold functions is not empty.",
312
+ vorschlag: 'Gib den Modulen {n} Funktionen oder entferne sie.',
269
313
  },
270
314
  'R-26': {
271
- plain: "A data format in the model isn't linked to the schema code that defines it → link it to the schema (or mark it concept/outside).",
272
- se: "Realized `SCHEMA` with no valid `realRef` `{file, symbol}` (graph↔Zod binding); else `concept:true` / `external:true` (CR-211/228).",
315
+ plain: "Building has started, and a data format in the model isn't linked to the schema code that defines it yet → link it to the schema (or mark it as defined outside).",
316
+ se: "`SCHEMA` with no valid `realRef` `{file, symbol}` (graph↔Zod binding); else `external:true` (CR-211/228)." +
317
+ " Stage 11: due only once the build is open — an open CR or a first `realRef`/`testRefs` in the graph; before that it is not evaluated, not passed (CR-SM-395).",
318
+ vorschlag: 'Verbinde die Datenformate {n} mit ihrem Schema im Code.',
273
319
  },
274
320
  'R-29': {
275
321
  plain: "Two acceptances claim the same test file, so a red run cannot be traced to one of them and the gate counts that evidence twice → give the file to the one acceptance it really proves, or split it.",
276
322
  se: "Test file exclusivity (CR-SM-231): every file in `attributes.testRefs` belongs to at most one `TEST`. An acceptance may name n files (1:n) — a file may not name n acceptances. Severity `error`, deliberately sharper than R-19/R-20: a doubly claimed file makes gate numbers wrong, which is a mis-measurement, not a completeness signal. Purely structural — the file need not exist to be claimed twice.",
323
+ vorschlag: 'Gib jede Testdatei von {n} nur einem Test.',
277
324
  },
278
325
  'R-30': {
279
326
  plain: "This function sits in no chain of effects, so nobody can say which use case it serves — and the checks that would prove its wiring never look at it → add it to the chain of the use case it belongs to.",
280
327
  se: "FUNC belongs to a function chain (CR-GC-366): a `FUNC` needs an incoming `FCHAIN -compose-> FUNC`, directly or inherited from a parent `FUNC` it decomposes from. R-15 demanded the opposite direction — that a chain has functions — and nothing demanded that a function has a chain. That gap is load-bearing: IO-01 (FLOW paths between chain members) and R-21 (integration test per chain) both scope themselves to a chain, so a function outside every chain falls through both nets silently. Severity `warning`, not error: on a real model this fires on the majority of functions, and an error would block every further mutation through the delta gate.",
328
+ vorschlag: 'Ordne die Funktionen {n} der Kette ihres Ablaufs zu.',
281
329
  },
282
330
  'R-31': {
283
331
  plain: "This function has no input or no output, so it is a dead block in the picture — only an actor is allowed to be an end point → connect it to a flow on the missing side.",
284
332
  se: "FUNC is wired (CR-GC-366): a `FUNC` needs at least one incoming `FLOW -io-> FUNC` and one outgoing `FUNC -io-> FLOW`. Only an `ACTOR` may terminate a chain. R-10 asks the same question from the FLOW side ('does this flow have a producer and a consumer?') and therefore never sees a function with no io edge at all — it does not appear in the FLOW loop. IO-01 presupposes chain membership and misses it too. One finding per FUNC naming the missing side(s), not one per side: otherwise the counter exceeds its own denominator contribution, the mis-measurement documented in CR-SM-242.",
333
+ vorschlag: 'Verbinde die Funktionen {n} auf der fehlenden Seite mit einem Datenfluss.',
285
334
  },
286
335
  'RC-01': {
287
336
  plain: "A function points to code that isn't there anymore (file moved or name changed) → repoint it to the current code.",
288
337
  se: "FUNC `realRef` that does not resolve: file missing on disk or symbol not declared in it (CR-GC-253 conformance over CodeFacts).",
338
+ vorschlag: 'Korrigiere die Code-Verweise der Funktionen {n}, sie zeigen ins Leere.',
289
339
  },
290
340
  'RC-02': {
291
341
  plain: "A test points to a test file or test name that isn't there anymore → repoint it to the current test.",
292
342
  se: "A `testRefs` entry that does not resolve: file missing or `case` not declared as an it/test/describe (CR-GC-253). The message names the concrete path — with n entries the node id alone is not actionable.",
343
+ vorschlag: 'Korrigiere die Testverweise von {n}, die Testfälle gibt es nicht.',
293
344
  },
294
345
  'RC-03': {
295
346
  plain: "A data format points to schema code that isn't there anymore (file moved or export renamed) → repoint it to the current schema.",
296
347
  se: "SCHEMA `realRef` that does not resolve: file missing on disk or symbol not a declared export in it (CR-211/228 conformance over CodeFacts).",
348
+ vorschlag: 'Korrigiere die Code-Verweise der Datenformate {n}, sie zeigen ins Leere.',
297
349
  },
298
350
  'RC-04': {
299
351
  plain: "A data format is defined but the function on that interface never actually checks incoming data against it → validate with it there.",
300
352
  se: "Bound `SCHEMA` whose symbol is not imported+parsed (`.parse`/`.safeParse`) in any realized `FUNC` io-connected to it (CR-211); warn — the parse may sit in a framework layer.",
353
+ vorschlag: 'Lies die Datenformate {n} im Code an der Schnittstelle, an der das Modell sie führt.',
301
354
  },
302
355
  'RC-05': {
303
356
  plain: "Code in one building block imports code in another, but the model never says those two are connected → draw the connection in the model, or drop the import.",
304
357
  se: "File import crossing a `MOD` boundary with no documenting graph structure (no io/FLOW between the modules) — undocumented cross-module dependency (CR-212); warn indicator, not a blocker.",
358
+ vorschlag: 'Trage die Abhängigkeit der Module {n} ins Modell ein oder entferne den Import.',
305
359
  },
306
360
  'RC-06': {
307
361
  plain: "This element points at code in a package your project does not actually install → either add the package, or point at the one that owns the symbol now.",
308
362
  se: "An `external: true` `realRef` names a package that is in neither `dependencies` nor `devDependencies` of the consumer. Absent dependency data is SILENCE, not a violation — the extractor never looked, and treating that as \"declares nothing\" would report every external binding at once (CR-SM-262).",
363
+ vorschlag: 'Trage die Pakete, auf die {n} verweisen, als Abhängigkeit ein.',
309
364
  },
310
365
  'RC-07': {
311
366
  plain: "A change request is marked done in the model but still open in the folder (or the other way round), or an open change request has no entry in the model → the folder decides; fix the model.",
312
367
  se: "`CR` node whose `status` (closed = done; CR-SM-362) contradicts `docs/cr/open|done/`, or an OPEN CR file with no `CR` node (anchored at the first `SYS`). Nodes without a file are not reported — history. Absent `crFiles` is SILENCE (CR-SM-329).",
368
+ vorschlag: 'Gleiche die Änderungsaufträge {n} mit ihren Dateien ab.',
313
369
  },
314
370
  'RC-08': {
315
371
  plain: "A data contract in the model points at a type, which vanishes at runtime → write it as a Zod schema, so whoever produces the data can prove it and whoever reads it can check it.",
316
372
  se: "`SCHEMA` whose `realRef` symbol is declared but is not a Zod schema (extractor field `zodSymbols`). Every producer needs a checkable schema — \"nobody parses it\" only means the reader is not known yet. Absent `zodSymbols` is SILENCE. Owns the type-binding cause: RC-04 stays quiet on such a SCHEMA (CR-SM-358).",
373
+ vorschlag: 'Binde die Datenformate {n} an ein Schema statt an einen Typ.',
317
374
  },
318
375
  'RC-09': {
319
376
  plain: "Code somewhere reads a data contract on its own, but the model does not know that place → go through the one translator the model names, or add the new translator to the model.",
320
377
  se: "Zod-bound `SCHEMA` parsed (import + `.parse`/`.safeParse`) in a file that is neither its definition nor the `realRef` of a `FUNC` io-connected to a `FLOW` of this SCHEMA. The first code → model check: a second translator of one contract is a parallel path (spike CR-GC-637 — such paths share a contract, they are not similar). One finding per SCHEMA; test files exempt; runs only with `fileScope: 'all'` (CR-SM-358).",
378
+ vorschlag: 'Prüfe, wo die Datenformate {n} außerhalb ihrer Schnittstelle gelesen werden.',
321
379
  },
322
380
  'RC-10': {
323
381
  plain: "No file in the code can be assigned to this building block, so nobody can check whether its imports cross boundaries the model does not know → give the block its source folder, or point one of its functions at its code.",
324
- se: "`MOD` with neither a `path` attribute nor an allocated `FUNC` carrying a bound `realRef` — the only two ways a file resolves to a module. Without either, RC-05 and the boundary measurement are blind for this module by construction (sigllm: 0 RC-05 findings at 19 % import coverage, 8 at 81 %). The message names the cost from `importCoverage`. `concept`/`external` modules are exempt, as for R-20 (CR-SM-344).",
382
+ se: "`MOD` with neither a `path` attribute nor an allocated `FUNC` carrying a bound `realRef` — the only two ways a file resolves to a module. Without either, RC-05 and the boundary measurement are blind for this module by construction (sigllm: 0 RC-05 findings at 19 % import coverage, 8 at 81 %). The message names the cost from `importCoverage`. `external` modules are exempt, as for R-20 (CR-SM-344). Stage 11: due only once the build is open — an open CR or a first `realRef`/`testRefs` in the graph; before that it is not evaluated, not passed (CR-SM-395).",
383
+ vorschlag: 'Gib den Modulen {n} ihren Quellordner.',
325
384
  },
326
385
  'RD-01': {
327
386
  plain: "A smallest-piece feature has nothing built to fulfil it → add what implements it.",
328
387
  se: "Leaf `REQ` (no `compose`→`REQ` children) with no `satisfy` from a `FUNC`/`FCHAIN`/`MOD`/`SYS`.",
329
388
  prompt: "se:close-violations",
389
+ vorschlag: 'Lege an, was die Anforderungen {n} erfüllt.',
330
390
  },
331
391
  'RD-02': {
332
392
  plain: "You split a feature into smaller features but you're also building the big one directly → build only the small pieces, not both.",
333
393
  se: "Parent `REQ` (has `compose`→`REQ` children) carrying a direct `FUNC` `satisfy`; the satisfy belongs on the children.",
394
+ vorschlag: 'Lass die Anforderungen {n} nur über ihre Teilanforderungen erfüllen.',
334
395
  },
335
396
  'RD-04': {
336
397
  plain: "One thing has more than 9 parts directly under it → group them, so each level stays readable.",
337
398
  se: "Decomposition breadth above `metricPolicy.decompositionBreadth.warning` children on one level — `FUNC` `compose` `FUNC`, `SYS` `compose` `MOD`, a `MOD`'s sub-`MOD`s plus its own leaf `FUNC` (`allocate`), and the root `FUNC` forest anchored at `SYS` (CR-SM-282). Default 9, the upper end of 7±2 (CR-SM-296). CR-SM-311: a module level counts its own functions again — breadth, not size; module coupling is R-04. The lower bound is RD-05.",
399
+ vorschlag: 'Gruppiere die Teile unter {n}, es sind zu viele auf einer Ebene.',
338
400
  },
339
401
  'RD-05': {
340
402
  plain: "A level has only one or two parts under it → it groups nothing; fold it into the level above, or gather the parts that belong together under it.",
341
- se: "Decomposition breadth below `metricPolicy.decompositionBreadth.min` (default 3, exclusive) on one level, counted exactly like RD-04 (CR-SM-311, Z3). A level abstracts nothing below it. The finding carries no `value`/`threshold` and does not enter the steering score: it is readability, not boundary width. A level with no children at all is not this rule (empty MOD: R-23; FUNC without children is a leaf).",
403
+ se: "Decomposition breadth below `metricPolicy.decompositionBreadth.min` (default 3, exclusive) on one level, counted exactly like RD-04 (CR-SM-311, Z3). A level abstracts nothing below it. The finding carries no `value`/`threshold` and does not enter the steering score: it is readability, not boundary width. A level with no children at all is not this rule (empty MOD: R-23; FUNC without children is a leaf). The root level directly under `SYS` (`SYS` `compose` `MOD`, root `FUNC` forest) is exempt — there is no level above it, and one module or one root function is an architecture decision (CR-SM-388); RD-04 still applies there.",
404
+ vorschlag: 'Löse die Ebene {n} in die Ebene darüber auf oder sammle unter ihr, was zusammengehört.',
342
405
  },
343
406
  'SC-02': {
344
407
  plain: "A data format is defined but nothing uses it → connect it to the data it describes, or drop it.",
345
408
  se: "`SCHEMA` not referenced by any `FLOW` via a `relation` trace.",
409
+ vorschlag: 'Verbinde das Datenformat {n} mit seinem Datenfluss oder entferne es.',
346
410
  },
347
411
  'UC-01': {
348
412
  plain: "A scenario says what someone wants to do but never says what the system must provide → write down the requirements it needs.",
349
413
  se: "`UC` with no `compose` trace to any `REQ`. The use case carries no requirement content.",
350
414
  prompt: "se:author-req",
415
+ vorschlag: 'Lege für die Abläufe {n} Anforderungen mit Test an: fachliche je Funktion, Ende-zu-Ende-Vorgaben an der Kette.',
351
416
  },
352
417
  'UC-02': {
353
418
  plain: "A scenario has nobody who triggers it → name who or what starts it.",
354
419
  se: "`UC` that no `ACTOR` reaches: the one legal path is `ACTOR -io-> FLOW -io-> FUNC` (or back, `FUNC -io-> FLOW -io-> ACTOR`), the FUNC a member of one of the UC's chains (`UC -compose-> FCHAIN -compose-> FUNC`). A direct `ACTOR -io-> UC` is rejected by R-18. No skill prompt (CR-SM-370): `se:author-uc` shows creating UCs and `se:author-actor` says to leave actors unwired — neither is this work.",
420
+ vorschlag: 'Lege für die Abläufe {n} die Funktionen an, die der Nutzer über einen Datenfluss auslöst.',
355
421
  },
356
422
  'UC-03': {
357
423
  plain: "A scenario says what should be possible but not how it runs → describe the steps as a chain of functions.",
358
424
  se: "`UC` with no `compose` trace to an `FCHAIN`. No behavioural scenario is declared.",
359
425
  prompt: "se:author-uc",
426
+ vorschlag: 'Beschreibe die Abläufe {n} als Kette von Funktionen.',
360
427
  },
361
428
  'UC-04': {
362
429
  plain: "A scenario has no real description, or still carries a placeholder like TBD → write what the user actually wants to achieve.",
363
430
  se: "`UC` description shorter than 10 characters or containing TBD/TODO/FIXME/placeholder/XXX. Description IS the goal (CR-150).",
364
431
  prompt: "se:author-uc",
432
+ vorschlag: 'Beschreibe das Ziel der Abläufe {n}.',
365
433
  },
366
434
  'VR-01': {
367
435
  plain: "A test exists but no result was ever recorded, so nobody knows if it passed → record the outcome.",
368
436
  se: "`TEST` with no `testResult` attribute — assumed pending, never assumed green.",
369
437
  },
370
- // CR-SM-355: Task-Ausgaenge — sichtbar nur im Task trade / irr.
438
+ // CR-SM-355: die Ausgaenge von Variantenvergleich und Annahmen-Review. Sie melden erst, wenn die
439
+ // Analyse gestempelt ist — vorher schweigen sie von selbst (CR-SM-395).
371
440
  'TR-01': {
372
441
  plain: "The trade study is stamped, but the decision it produced is not on record as a CR (or the CR it names is missing or carries no decides edge) → record the decision as a CR and list its id in the stamp.",
373
442
  se: "Task outcome rule (CR-SM-355): `analysisFreshness.trade.crRefs` names existing CR elements, each carrying a `relation` edge labelled `decides` (the SP-1 decision record).",
374
443
  prompt: "se-trade",
444
+ vorschlag: 'Halte die Entscheidung des Variantenvergleichs für {n} als Änderungsauftrag fest.',
375
445
  },
376
446
  'IR-01': {
377
- plain: "The assumption review names a CR that does not exist → fix the reference or add the CR; an empty list is fine when no assumption was load-bearing.",
378
- se: "Task outcome rule (CR-SM-355): every id in `analysisFreshness.assumption-review.crRefs` resolves to a CR element; empty is a legitimate outcome (low-risk assumptions stay in the record).",
447
+ plain: "The assumption review names a requirement that does not exist → fix the reference or add the requirement with its test; an empty list is fine when no assumption was load-bearing.",
448
+ se: "Task outcome rule (CR-SM-355, CR-SM-397): every id in `analysisFreshness.assumption-review.reqRefs` resolves to a `REQ` element; empty is a legitimate outcome (low-risk assumptions stay in the record). The verifying `TEST` is R-01's finding. An analysis leaves requirements, never a build order.",
379
449
  prompt: "se-irr",
450
+ vorschlag: 'Lege die Anforderungen an, die das Annahmen-Review für {n} nennt.',
380
451
  },
381
452
  };
@@ -6,6 +6,7 @@
6
6
  import { z } from 'zod/v4';
7
7
  import type { OntologyGraph } from './ontology.js';
8
8
  import type { MetricPolicy } from './policy.js';
9
+ import type { RuleRole, RuleStage } from './readiness.js';
9
10
  export declare const RuleSeverity: z.ZodEnum<{
10
11
  error: "error";
11
12
  info: "info";
@@ -306,6 +307,14 @@ export interface RuleDefinition {
306
307
  id: string;
307
308
  name: string;
308
309
  severity: 'error' | 'warning' | 'info';
310
+ /**
311
+ * CR-SM-395: die STUFE — die spaeteste Menge, die die Regel braucht (`STAGE_SETS`), oder `'immer'`.
312
+ * Aus ihr folgen Rang und Marke (`markOfStage`); es gibt keine zweite Zuordnung. Pflichtfeld: ein
313
+ * Regeleintrag ohne Stufe bricht den Build.
314
+ */
315
+ stage: RuleStage;
316
+ /** CR-SM-395: `existence` | `analysis` — oder nichts. */
317
+ role?: RuleRole;
309
318
  /**
310
319
  * CR-SM-236: `policy` steht jeder Regel zur Verfuegung, damit eine Urteilsschwelle nirgends
311
320
  * als Literal im Regelcode zurueckbleibt. Regeln ohne Schwelle deklarieren den Parameter
@@ -369,6 +378,15 @@ export declare function decomposedFuncs(graph: OntologyGraph): Set<string>;
369
378
  * die zweite Wahrheit, die CR-SM-286/-302 beseitigt haben.
370
379
  */
371
380
  export declare function flowProducers(graph: OntologyGraph): Map<string, Set<string>>;
381
+ /** Der Anker eines Befunds an einem Graphen ohne SYS — kein Element traegt diese Id. */
382
+ export declare const GRAPH_ANCHOR = "graph";
383
+ /**
384
+ * CR-SM-395: das UNGEBAUTE — die Elemente, an denen die Praesenzregeln der Bindung melden wuerden
385
+ * (R-19 TEST, R-20 FUNC, R-26 SCHEMA), unabhaengig davon, ob sie schon faellig sind. EINE
386
+ * Definition samt Ausnahmen (`external`, Zerlegungs-Eltern mit gebundenen Kindern): AF-05 fragt
387
+ * damit „gibt es etwas zu bauen?", ohne die Ausnahmen ein zweites Mal zu schreiben.
388
+ */
389
+ export declare function unbuiltElementIds(graph: OntologyGraph): string[];
372
390
  export declare const V3_RULES: RuleDefinition[];
373
391
  /** Run all rules against a graph. CR-SM-236: `policy` ist Pflicht — wie bei `evaluateAllRules`. */
374
392
  export declare function evaluateRules(graph: OntologyGraph, policy: MetricPolicy): RuleViolation[];