@untangle-code/complexity 0.0.0-stage → 0.1.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 (105) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +235 -2
  4. package/THIRD_PARTY_LICENSES.md +24 -0
  5. package/dist/aggregator.d.ts +28 -0
  6. package/dist/aggregator.d.ts.map +1 -0
  7. package/dist/aggregator.js +77 -0
  8. package/dist/aggregator.js.map +1 -0
  9. package/dist/assemble.d.ts +50 -0
  10. package/dist/assemble.d.ts.map +1 -0
  11. package/dist/assemble.js +43 -0
  12. package/dist/assemble.js.map +1 -0
  13. package/dist/cognitive.d.ts +62 -0
  14. package/dist/cognitive.d.ts.map +1 -0
  15. package/dist/cognitive.js +62 -0
  16. package/dist/cognitive.js.map +1 -0
  17. package/dist/cyclomatic.d.ts +29 -0
  18. package/dist/cyclomatic.d.ts.map +1 -0
  19. package/dist/cyclomatic.js +52 -0
  20. package/dist/cyclomatic.js.map +1 -0
  21. package/dist/entropy.d.ts +5 -0
  22. package/dist/entropy.d.ts.map +1 -0
  23. package/dist/entropy.js +29 -0
  24. package/dist/entropy.js.map +1 -0
  25. package/dist/explain.d.ts +22 -0
  26. package/dist/explain.d.ts.map +1 -0
  27. package/dist/explain.js +35 -0
  28. package/dist/explain.js.map +1 -0
  29. package/dist/halstead.d.ts +23 -0
  30. package/dist/halstead.d.ts.map +1 -0
  31. package/dist/halstead.js +24 -0
  32. package/dist/halstead.js.map +1 -0
  33. package/dist/index.d.ts +35 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +34 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/ir/build-ir.d.ts +105 -0
  38. package/dist/ir/build-ir.d.ts.map +1 -0
  39. package/dist/ir/build-ir.js +267 -0
  40. package/dist/ir/build-ir.js.map +1 -0
  41. package/dist/maintainability.d.ts +15 -0
  42. package/dist/maintainability.d.ts.map +1 -0
  43. package/dist/maintainability.js +10 -0
  44. package/dist/maintainability.js.map +1 -0
  45. package/dist/node-kind-heuristics.d.ts +24 -0
  46. package/dist/node-kind-heuristics.d.ts.map +1 -0
  47. package/dist/node-kind-heuristics.js +37 -0
  48. package/dist/node-kind-heuristics.js.map +1 -0
  49. package/dist/prose/metrics.d.ts +81 -0
  50. package/dist/prose/metrics.d.ts.map +1 -0
  51. package/dist/prose/metrics.js +103 -0
  52. package/dist/prose/metrics.js.map +1 -0
  53. package/dist/scope-aggregate.d.ts +229 -0
  54. package/dist/scope-aggregate.d.ts.map +1 -0
  55. package/dist/scope-aggregate.js +588 -0
  56. package/dist/scope-aggregate.js.map +1 -0
  57. package/dist/scope-identity.d.ts +85 -0
  58. package/dist/scope-identity.d.ts.map +1 -0
  59. package/dist/scope-identity.js +144 -0
  60. package/dist/scope-identity.js.map +1 -0
  61. package/dist/scope.d.ts +36 -0
  62. package/dist/scope.d.ts.map +1 -0
  63. package/dist/scope.js +60 -0
  64. package/dist/scope.js.map +1 -0
  65. package/dist/structural.d.ts +30 -0
  66. package/dist/structural.d.ts.map +1 -0
  67. package/dist/structural.js +98 -0
  68. package/dist/structural.js.map +1 -0
  69. package/dist/syntactic.d.ts +35 -0
  70. package/dist/syntactic.d.ts.map +1 -0
  71. package/dist/syntactic.js +143 -0
  72. package/dist/syntactic.js.map +1 -0
  73. package/dist/text-lines.d.ts +34 -0
  74. package/dist/text-lines.d.ts.map +1 -0
  75. package/dist/text-lines.js +60 -0
  76. package/dist/text-lines.js.map +1 -0
  77. package/dist/textual.d.ts +28 -0
  78. package/dist/textual.d.ts.map +1 -0
  79. package/dist/textual.js +75 -0
  80. package/dist/textual.js.map +1 -0
  81. package/dist/types.d.ts +112 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +2 -0
  84. package/dist/types.js.map +1 -0
  85. package/package.json +60 -3
  86. package/src/aggregator.ts +105 -0
  87. package/src/assemble.ts +109 -0
  88. package/src/cognitive.ts +127 -0
  89. package/src/cyclomatic.ts +78 -0
  90. package/src/entropy.ts +30 -0
  91. package/src/explain.ts +64 -0
  92. package/src/halstead.ts +54 -0
  93. package/src/index.ts +85 -0
  94. package/src/ir/build-ir.ts +411 -0
  95. package/src/maintainability.ts +29 -0
  96. package/src/node-kind-heuristics.ts +55 -0
  97. package/src/prose/metrics.ts +201 -0
  98. package/src/scope-aggregate.ts +775 -0
  99. package/src/scope-identity.ts +240 -0
  100. package/src/scope.ts +77 -0
  101. package/src/structural.ts +132 -0
  102. package/src/syntactic.ts +183 -0
  103. package/src/text-lines.ts +90 -0
  104. package/src/textual.ts +119 -0
  105. package/src/types.ts +121 -0
@@ -0,0 +1,588 @@
1
+ /**
2
+ * Aggregation ueber einen Scope-BAUM, ohne Doppelzaehlung (WP-82; spec.md
3
+ * §16.10, docs/BUILD_PLAN.md E4).
4
+ *
5
+ * ## Das Problem
6
+ *
7
+ * `aggregate()` in `aggregator.ts` dedupliziert ueber `metricsScopeId` und
8
+ * loest damit genau einen Fall: dasselbe Retrieval-Fragment zweimal in der
9
+ * Eingabe. Es loest NICHT den Fall, um den es hier geht — verschachtelte
10
+ * Scopes. `buildSymbolIR()` bezieht bewusst jeden Nachfahren-Scope in die IR
11
+ * des Zielscopes ein (siehe `ir/build-ir.ts`, "documented nesting context"
12
+ * nach spec.md §16.4): der `file`-Scope traegt also den Kontrollfluss ALLER
13
+ * Klassen, Methoden und Closures der Datei, die Methode den ihrer Closures.
14
+ * Jeder dieser Scopes hat eine eigene, gueltige `metricsScopeId` — die
15
+ * Deduplizierung greift nicht, und `sum` zaehlt denselben Quelltext einmal
16
+ * je umschliessendem Scope.
17
+ *
18
+ * Am eigenen Repo gemessen (siehe `scripts/complexity-report.mjs`): naiv
19
+ * summiert ergibt cognitive rund das Dreifache der Summe, die jeden Scope
20
+ * genau einmal zaehlt. Eine Hotspot-Liste auf dieser Basis steuert in die
21
+ * falsche Richtung.
22
+ *
23
+ * ## Die drei Lesarten
24
+ *
25
+ * "Summe ueber ein Paket" ist ohne Angabe der Lesart bedeutungslos. Dieses
26
+ * Modul kennt genau drei, alle drei zaehlen jeden Scope GENAU EINMAL, und
27
+ * sie unterscheiden sich ausschliesslich darin, wie viel Nesting-Kontext ein
28
+ * Konstrukt mitbekommt:
29
+ *
30
+ * - `"top_level"` (Datei-Lesart): Summe der `inclusiveValue` ueber die
31
+ * Wurzel-Scopes. Jedes Konstrukt zaehlt einmal, mit dem VOLLEN
32
+ * Nesting-Kontext bis zur Wurzel — jede umschliessende Funktion zaehlt als
33
+ * Nesting-Ebene. Beantwortet: "wie schwer ist diese Datei am Stueck zu
34
+ * lesen".
35
+ * - `"execution_unit"` (Funktions-Lesart, DEFAULT): Summe der
36
+ * `inclusiveValue` ueber die AEUSSERSTEN Ausfuehrungseinheiten (Funktion,
37
+ * Methode, Konstruktor) plus die `selfValue` aller Scopes, die selbst keine
38
+ * Ausfuehrungseinheit sind und auch keine ueber sich haben (Datei, Klasse,
39
+ * Interface, Namespace). Der Nesting-Zaehler startet bei jeder aeussersten
40
+ * Funktion neu; verschachtelte Closures bleiben — wie von spec.md §16.4
41
+ * verlangt — Teil ihrer umschliessenden Funktion. Das ist die Lesart, die
42
+ * der verbreiteten "cognitive complexity je Funktion, danach aufsummiert"
43
+ * Konvention entspricht und damit die einzige, die einer Gegenprobe gegen
44
+ * ein etabliertes Werkzeug (X8) standhaelt.
45
+ * - `"self"` (Eigenanteil-Lesart): Summe der `selfValue` ueber ALLE Scopes.
46
+ * Der Nesting-Zaehler startet in jedem Scope neu, auch in einer Closure.
47
+ * Untere Schranke; nuetzlich, um den Anteil sichtbar zu machen, den reines
48
+ * Nesting am Gesamtwert hat.
49
+ *
50
+ * Fuer eine Metrik OHNE Sockel je Scope (`perScopeBase === 0`, also cognitive)
51
+ * gilt strukturell `self <= execution_unit <= top_level`, und zwar als Folge
52
+ * der Kerninvariante: die Differenzen sind nicht Rauschen, sondern genau der
53
+ * Nesting-Aufschlag der jeweils zusaetzlich beruecksichtigten Ebenen (belegt
54
+ * in `scope-aggregate.test.ts`).
55
+ *
56
+ * ## Woraus die Doppelzaehlungsfreiheit tatsaechlich folgt
57
+ *
58
+ * Nicht aus `checkScopeTreeInvariants`. Deren Kernpruefung
59
+ * `children_exceed_parent` ist eine EINSEITIGE Schranke
60
+ * (`self + Summe Kinder <= inclusive`): sie faengt einen zu KLEINEN
61
+ * Elternwert, also fehlenden Inhalt. Ein zu GROSSER Elternwert — der Fall, in
62
+ * dem ein Kindbeitrag zweimal im Elternwert steckt — erfuellt sie erst recht
63
+ * und bleibt damit unentdeckt. Aus Werten allein ist er auch nicht
64
+ * entscheidbar: ein aufgeblaehter `inclusiveValue` sieht genauso aus wie ein
65
+ * Scope, der im eigenen Koerper einfach viel Kontrollfluss traegt.
66
+ *
67
+ * Was dieses Modul stattdessen ZUSICHERT und mit `checkScopeCoverage`
68
+ * NACHPRUEFT, ist die strukturelle Aussage: in jeder der drei Lesarten geht
69
+ * jeder Scope in GENAU EINEN Summanden ein — entweder als eigener Summand
70
+ * oder als Nachfahre genau eines Summanden, der mit `inclusiveValue` zaehlt.
71
+ * Damit kann keine Lesart denselben Quelltext zweimal aufaddieren. Das ist
72
+ * die Zusicherung, die die Summen tragen; die Werttreue der einzelnen
73
+ * `inclusiveValue`s liegt beim Aufrufer, der sie berechnet hat.
74
+ *
75
+ * Fuer eine Metrik MIT Sockel (`perScopeBase > 0`, also cyclomatic:
76
+ * `M = 1 + decision_points`) kehrt sich die Reihenfolge um, und das ist
77
+ * korrekt: die `self`-Lesart zaehlt den Sockel einmal JE SCOPE, die
78
+ * `top_level`-Lesart nur einmal je Datei. Die drei Zahlen bleiben
79
+ * doppelzaehlungsfrei — sie beantworten nur verschiedene Fragen. Wer sie
80
+ * nebeneinander zeigt, muss den Sockel dazusagen.
81
+ *
82
+ * ## Warum es KEINE Blatt-Lesart gibt
83
+ *
84
+ * "Summe der Blatt-Scopes" waere die naheliegende vierte Lesart und ist
85
+ * FALSCH: der Kontrollfluss, der direkt im Koerper eines Scopes MIT Kindern
86
+ * steht (eine `if`-Kette in einer Methode, die ausserdem eine Closure
87
+ * definiert), gehoert keinem Blatt und faellt ersatzlos weg. Das ist kein
88
+ * Deduplizieren, sondern stilles Verlieren von Inhalt — genau das, was E4
89
+ * verbietet. `ScopeTreeAggregateV1.leafOnlySum` weist die Zahl trotzdem aus,
90
+ * aber ausdruecklich als Diagnose zusammen mit `leafOnlyDroppedAmount`, dem
91
+ * Betrag, den sie verschluckt.
92
+ *
93
+ * ## Determinismus
94
+ *
95
+ * Kein `localeCompare`, kein `Date.now()`, kein `Math.random()`. Reihenfolgen
96
+ * werden ueber `compareCodepoints` aus `@untangle-code/domain` hergestellt.
97
+ */
98
+ import { compareCodepoints, UntangleError } from "@untangle-code/domain";
99
+ /** Die drei definierten Lesarten einer Scope-Summe. */
100
+ export const SCOPE_SUM_READINGS = ["top_level", "execution_unit", "self"];
101
+ /** Geschlossene Menge der Invariantenverstoesse. Ein Verstoss ist ein Fehler, kein Hinweis. */
102
+ export const SCOPE_INVARIANT_CODES = [
103
+ "duplicate_scope_id",
104
+ "unknown_parent",
105
+ "parent_cycle",
106
+ "negative_value",
107
+ "self_exceeds_inclusive",
108
+ "children_exceed_parent",
109
+ "leaf_self_differs_from_inclusive",
110
+ "scope_counted_twice",
111
+ "scope_uncounted",
112
+ ];
113
+ /**
114
+ * Die Felder, in denen sich zwei Eintraege mit derselben `metricsScopeId`
115
+ * unterscheiden — als LISTE, nicht als Ja/Nein.
116
+ *
117
+ * WP-186: Die Begruendung im Verstoss darf nicht behaupten, „die Werte
118
+ * weichen ab", und dann zweimal dieselbe Zahl drucken. Genau das geschah,
119
+ * sobald der Unterschied in `parentScopeId` oder `executionUnit` lag: der
120
+ * Text nannte `inclusive`/`self`, die dort identisch waren, und das
121
+ * tatsaechlich abweichende Feld kam nirgends vor. Wer so etwas liest, sucht
122
+ * einen Fehler in einer Zahl, die stimmt.
123
+ *
124
+ * WP-200: `sloc` gehoert dazu. Es blieb ausserhalb des Vergleichs, obwohl es
125
+ * das GEWICHT im SLOC-gewichteten Mittel von `aggregate()` stellt: zwei
126
+ * Eintraege mit derselben Id und verschiedenem `sloc` galten als identisch,
127
+ * der zweite wurde ohne Verstoss verworfen — und mit ihm sein Gewicht. Der
128
+ * Mittelwert verschob sich, und nichts sagte es.
129
+ */
130
+ function differingFields(a, b) {
131
+ const differing = [];
132
+ if (a.inclusiveValue !== b.inclusiveValue) {
133
+ differing.push(`inclusive ${String(b.inclusiveValue)} vs. ${String(a.inclusiveValue)}`);
134
+ }
135
+ if (a.selfValue !== b.selfValue) {
136
+ differing.push(`self ${String(b.selfValue)} vs. ${String(a.selfValue)}`);
137
+ }
138
+ if (a.executionUnit !== b.executionUnit) {
139
+ differing.push(`executionUnit ${String(b.executionUnit)} vs. ${String(a.executionUnit)}`);
140
+ }
141
+ if (a.parentScopeId !== b.parentScopeId) {
142
+ differing.push(`parentScopeId ${b.parentScopeId ?? "(none)"} vs. ${a.parentScopeId ?? "(none)"}`);
143
+ }
144
+ if (a.sloc !== b.sloc) {
145
+ differing.push(`sloc ${String(b.sloc ?? "(none)")} vs. ${String(a.sloc ?? "(none)")}`);
146
+ }
147
+ return differing;
148
+ }
149
+ /**
150
+ * Dedupliziert nach `metricsScopeId` (erstes Vorkommen gewinnt, wie
151
+ * `aggregate()`, spec.md §16.10: doppelte Retrieval-Fragmente MUESSEN ueber
152
+ * `metrics_scope_id` dedupliziert werden) und meldet dabei jede
153
+ * WIDERSPRUECHLICHE Wiederholung als Verstoss: zwei gleiche Ids mit
154
+ * verschiedenen Werten sind keine harmlose Dublette, sondern ein Zeichen,
155
+ * dass die Ids nicht das identifizieren, was sie sollen.
156
+ *
157
+ * ACHTUNG FUER AUFRUFER — was `duplicatesDropped` bedeutet: eine
158
+ * Wiederholung mit ZUFAELLIG gleichen Werten ist von einer echten Dublette
159
+ * nicht zu unterscheiden und wird deshalb ohne Verstoss verworfen. Wer keine
160
+ * wiederholten Retrieval-Fragmente in der Eingabe hat — wer also einen ECHTEN
161
+ * Scope-Baum aggregiert, in dem jede Id genau einen Scope bezeichnen MUSS —
162
+ * fuer den ist jedes `duplicatesDropped > 0` verlorener Inhalt und muss als
163
+ * Fehler behandelt werden. Die Zahl steht deshalb in
164
+ * `ScopeTreeAggregateV1.duplicatesDropped`; sie zu ignorieren waere ein
165
+ * stilles Ueberspringen (E4). `scripts/complexity-report.mjs` bricht darauf
166
+ * ab.
167
+ */
168
+ function resolveTree(nodes) {
169
+ const byId = new Map();
170
+ const deduped = [];
171
+ const duplicateConflicts = [];
172
+ let duplicatesDropped = 0;
173
+ for (const node of nodes) {
174
+ const existing = byId.get(node.metricsScopeId);
175
+ if (existing !== undefined) {
176
+ duplicatesDropped++;
177
+ const differing = differingFields(existing, node);
178
+ if (differing.length > 0) {
179
+ duplicateConflicts.push({
180
+ code: "duplicate_scope_id",
181
+ metricsScopeId: node.metricsScopeId,
182
+ observed: node.inclusiveValue,
183
+ limit: existing.inclusiveValue,
184
+ detail: `metricsScopeId "${node.metricsScopeId}" appears more than once with differing ` +
185
+ `${differing.length === 1 ? "field" : "fields"}: ` +
186
+ `${differing.join(", ")}. The ID therefore does not identify exactly one scope; ` +
187
+ `a total over this set would be meaningless.`,
188
+ });
189
+ }
190
+ continue;
191
+ }
192
+ byId.set(node.metricsScopeId, node);
193
+ deduped.push(node);
194
+ }
195
+ deduped.sort((a, b) => compareCodepoints(a.metricsScopeId, b.metricsScopeId));
196
+ const childrenByParent = new Map();
197
+ for (const node of deduped) {
198
+ if (node.parentScopeId === undefined)
199
+ continue;
200
+ const siblings = childrenByParent.get(node.parentScopeId) ?? [];
201
+ siblings.push(node);
202
+ childrenByParent.set(node.parentScopeId, siblings);
203
+ }
204
+ return { nodes: deduped, byId, childrenByParent, duplicatesDropped, duplicateConflicts };
205
+ }
206
+ /** True, wenn `node` in einer Elternkette liegt, die sich schliesst oder ins Leere laeuft. */
207
+ function ancestryProblem(node, byId) {
208
+ const seen = new Set([node.metricsScopeId]);
209
+ let current = node;
210
+ for (;;) {
211
+ const parentId = current.parentScopeId;
212
+ if (parentId === undefined)
213
+ return null;
214
+ if (seen.has(parentId))
215
+ return "cycle";
216
+ const parent = byId.get(parentId);
217
+ if (parent === undefined)
218
+ return "unknown_parent";
219
+ seen.add(parentId);
220
+ current = parent;
221
+ }
222
+ }
223
+ /**
224
+ * Prueft alle Invarianten des Scope-Baums und liefert JEDEN Verstoss mit
225
+ * Begruendung. Leere Liste heisst: der Baum traegt eine sinnvolle Summe.
226
+ *
227
+ * Geprueft wird:
228
+ * 1. `duplicate_scope_id` — dieselbe Id mit abweichenden Werten.
229
+ * 2. `unknown_parent` — `parentScopeId` zeigt auf einen Scope, der nicht in
230
+ * der Menge ist. Ihn stillschweigend als Wurzel zu behandeln waere ein
231
+ * E4-Verstoss: der Elternwert, gegen den geprueft werden muesste, fehlt.
232
+ * 3. `parent_cycle` — die Elternkette schliesst sich.
233
+ * 4. `negative_value` — negative Metrikwerte.
234
+ * 5. `self_exceeds_inclusive` — der Eigenanteil ist groesser als der Wert
235
+ * mit Nachfahren. Der Eigenanteil ist per Definition ein Teil davon.
236
+ * 6. `children_exceed_parent` — der Eigenanteil eines Scopes plus die Summe
237
+ * seiner direkten Kinder darf seinen eigenen Wert nicht ueberschreiten.
238
+ *
239
+ * WAS DIESE PRUEFUNG LEISTET UND WAS NICHT — sie ist eine EINSEITIGE
240
+ * Schranke (`self + Summe Kinder <= inclusive`) und darf deshalb nicht als
241
+ * Doppelzaehlungspruefung gelesen werden:
242
+ * - Sie schlaegt an, wenn der Elternwert ZU KLEIN ist, dem Elternwert
243
+ * also Inhalt seiner Kinder FEHLT (oder ein Kindwert zu gross ist).
244
+ * Ein Verstoss heisst: der Baum verliert Inhalt, nicht: er zaehlt
245
+ * doppelt.
246
+ * - Sie schlaegt NICHT an, wenn der Elternwert ZU GROSS ist — genau der
247
+ * Fall, in dem ein Kindbeitrag zweimal im Elternwert steckt. Ein
248
+ * aufgeblaehter `inclusiveValue` ist aus Werten allein nicht von einem
249
+ * Scope zu unterscheiden, der im eigenen Koerper viel Kontrollfluss
250
+ * traegt.
251
+ *
252
+ * Die Zusicherung "jeder Beitrag zaehlt genau einmal" leistet
253
+ * `checkScopeCoverage` auf der Struktur der jeweiligen Lesart, nicht
254
+ * diese Wertschranke.
255
+ * 7. `leaf_self_differs_from_inclusive` — ein Scope ohne Kinder hat keine
256
+ * Nachfahren, sein Eigenanteil MUSS also sein Gesamtwert sein. Weicht er
257
+ * ab, hat der Aufrufer die beiden Werte nicht aus demselben Scope
258
+ * berechnet.
259
+ *
260
+ * NICHT geprueft (und mit Absicht hier benannt statt verschwiegen): ein zu
261
+ * grosser `inclusiveValue` eines Scopes MIT Kindern. Siehe Punkt 6 und die
262
+ * Modul-Doku, Abschnitt "Woraus die Doppelzaehlungsfreiheit tatsaechlich
263
+ * folgt".
264
+ *
265
+ * Alle Wertvergleiche laufen auf `wert - perScopeBase` (siehe
266
+ * `ScopeTreeOptions.perScopeBase`).
267
+ */
268
+ export function checkScopeTreeInvariants(nodes, options = {}) {
269
+ const perScopeBase = options.perScopeBase ?? 0;
270
+ const epsilon = options.epsilon ?? 1e-9;
271
+ const tree = resolveTree(nodes);
272
+ const violations = [...tree.duplicateConflicts];
273
+ for (const node of tree.nodes) {
274
+ if (node.inclusiveValue < 0 || node.selfValue < 0) {
275
+ violations.push({
276
+ code: "negative_value",
277
+ metricsScopeId: node.metricsScopeId,
278
+ observed: Math.min(node.inclusiveValue, node.selfValue),
279
+ limit: 0,
280
+ detail: `Scope "${node.metricsScopeId}" has a negative metric value ` +
281
+ `(inclusive ${String(node.inclusiveValue)}, self ${String(node.selfValue)}). ` +
282
+ `Complexity metrics are non-negative.`,
283
+ });
284
+ }
285
+ const problem = ancestryProblem(node, tree.byId);
286
+ if (problem === "unknown_parent") {
287
+ violations.push({
288
+ code: "unknown_parent",
289
+ metricsScopeId: node.metricsScopeId,
290
+ observed: 0,
291
+ limit: 0,
292
+ detail: `Scope "${node.metricsScopeId}" references a scope through its parent chain ` +
293
+ `that is absent from the set. It is not treated as a root: without the parent value, ` +
294
+ `we cannot determine whether its contribution is already included there (E4).`,
295
+ });
296
+ }
297
+ else if (problem === "cycle") {
298
+ violations.push({
299
+ code: "parent_cycle",
300
+ metricsScopeId: node.metricsScopeId,
301
+ observed: 0,
302
+ limit: 0,
303
+ detail: `The parent chain of scope "${node.metricsScopeId}" closes a cycle. ` +
304
+ `A scope tree with a cycle has no root or well-defined total.`,
305
+ });
306
+ }
307
+ const inclusive = node.inclusiveValue - perScopeBase;
308
+ const own = node.selfValue - perScopeBase;
309
+ if (own > inclusive + epsilon) {
310
+ violations.push({
311
+ code: "self_exceeds_inclusive",
312
+ metricsScopeId: node.metricsScopeId,
313
+ observed: own,
314
+ limit: inclusive,
315
+ detail: `Scope "${node.metricsScopeId}": self contribution ${String(node.selfValue)} exceeds ` +
316
+ `the inclusive value ${String(node.inclusiveValue)}. The self contribution is part ` +
317
+ `of the total and cannot exceed it.`,
318
+ });
319
+ }
320
+ const children = tree.childrenByParent.get(node.metricsScopeId) ?? [];
321
+ if (children.length === 0) {
322
+ if (Math.abs(node.inclusiveValue - node.selfValue) > epsilon) {
323
+ violations.push({
324
+ code: "leaf_self_differs_from_inclusive",
325
+ metricsScopeId: node.metricsScopeId,
326
+ observed: node.selfValue,
327
+ limit: node.inclusiveValue,
328
+ detail: `Scope "${node.metricsScopeId}" has no child scopes, but its self contribution ` +
329
+ `${String(node.selfValue)} differs from the inclusive value ${String(node.inclusiveValue)}. ` +
330
+ `Without descendants, both values must be identical.`,
331
+ });
332
+ }
333
+ continue;
334
+ }
335
+ const childrenSum = children.reduce((sum, child) => sum + (child.inclusiveValue - perScopeBase), 0);
336
+ if (own + childrenSum > inclusive + epsilon) {
337
+ const childList = children
338
+ .map((child) => `${child.metricsScopeId}=${String(child.inclusiveValue)}`)
339
+ .join(", ");
340
+ violations.push({
341
+ code: "children_exceed_parent",
342
+ metricsScopeId: node.metricsScopeId,
343
+ observed: own + childrenSum,
344
+ limit: inclusive,
345
+ detail: `Scope "${node.metricsScopeId}": self contribution ${String(own)} plus the sum of ` +
346
+ `${String(children.length)} direct children ${String(childrenSum)} equals ` +
347
+ `${String(own + childrenSum)} and exceeds the parent value ${String(inclusive)} ` +
348
+ `(values after subtracting perScopeBase=${String(perScopeBase)}). Children: ${childList}. ` +
349
+ `The parent value is missing child content, or a child value is too large; ` +
350
+ `a root total would be too small. This one-sided bound cannot detect ` +
351
+ `a parent value that is too large; checkScopeCoverage checks that separately.`,
352
+ });
353
+ }
354
+ }
355
+ violations.sort((a, b) => compareCodepoints(a.metricsScopeId, b.metricsScopeId) || compareCodepoints(a.code, b.code));
356
+ return violations;
357
+ }
358
+ /**
359
+ * Wirft bei jedem Invariantenverstoss. Die Meldung nennt Anzahl und die
360
+ * ersten Verstoesse im Klartext; `context.violations` traegt die volle Liste.
361
+ *
362
+ * Geprueft wird in ZWEI Stufen: erst die Wert- und Bauminvarianten
363
+ * (`checkScopeTreeInvariants`), danach — nur wenn der Baum ueberhaupt
364
+ * wohlgeformt ist — die strukturelle Zaehlpruefung ueber alle drei Lesarten
365
+ * (`checkAllScopeCoverage`). Erst beide zusammen tragen die Aussage, dass die
366
+ * ausgegebenen Summen jeden Scope genau einmal enthalten; die Wertschranke
367
+ * allein taete es nicht (siehe Punkt 6 oben).
368
+ */
369
+ export function assertScopeTreeInvariants(nodes, options = {}) {
370
+ const treeViolations = checkScopeTreeInvariants(nodes, options);
371
+ const violations = treeViolations.length > 0 ? treeViolations : checkAllScopeCoverage(nodes);
372
+ if (violations.length === 0)
373
+ return;
374
+ const preview = violations
375
+ .slice(0, 3)
376
+ .map((violation) => `${violation.code}: ${violation.detail}`)
377
+ .join(" | ");
378
+ throw new UntangleError("ANALYSIS_INCOMPLETE", `scope tree invariants violated (${String(violations.length)} violation(s)): ${preview}`, { operation: "complexity.aggregateScopeTree", context: { violations } });
379
+ }
380
+ /**
381
+ * Liefert genau die Eintraege, die eine Lesart zaehlt — jeder Scope hoechstens
382
+ * einmal, jeweils mit dem fuer die Lesart richtigen Wert. Das Ergebnis geht
383
+ * unveraendert in `aggregate()`; damit gelten count/mean/median/p90/p95/max/
384
+ * Schwellenzaehlung (spec.md §16.10) auf einer doppelzaehlungsfreien Basis.
385
+ *
386
+ * Prueft KEINE Invarianten — dafuer ist `checkScopeTreeInvariants` da. Ein
387
+ * `unknown_parent` wird hier zwangslaeufig wie eine Wurzel behandelt; genau
388
+ * deshalb meldet die Pruefung ihn als Fehler, statt ihn zu tolerieren.
389
+ */
390
+ export function selectScopeEntries(nodes, reading) {
391
+ const tree = resolveTree(nodes);
392
+ const selection = selectionFor(tree, reading);
393
+ const entries = [];
394
+ for (const node of tree.nodes) {
395
+ const kind = selection.get(node.metricsScopeId);
396
+ if (kind === undefined)
397
+ continue;
398
+ const entry = {
399
+ metricsScopeId: node.metricsScopeId,
400
+ value: kind === "inclusive" ? node.inclusiveValue : node.selfValue,
401
+ };
402
+ if (node.sloc !== undefined)
403
+ entry.sloc = node.sloc;
404
+ entries.push(entry);
405
+ }
406
+ return entries;
407
+ }
408
+ /**
409
+ * Die Auswahl einer Lesart. Einzige Quelle der Wahrheit fuer
410
+ * `selectScopeEntries` UND `checkScopeCoverage`: die Pruefung soll dieselbe
411
+ * Auswahl sehen, die auch summiert wird, sonst prueft sie etwas anderes als
412
+ * das, was ausgegeben wird.
413
+ */
414
+ export function selectionForReading(nodes, reading) {
415
+ return selectionFor(resolveTree(nodes), reading);
416
+ }
417
+ function selectionFor(tree, reading) {
418
+ const selection = new Map();
419
+ for (const node of tree.nodes) {
420
+ switch (reading) {
421
+ case "self":
422
+ selection.set(node.metricsScopeId, "self");
423
+ break;
424
+ case "top_level":
425
+ if (node.parentScopeId === undefined || !tree.byId.has(node.parentScopeId)) {
426
+ selection.set(node.metricsScopeId, "inclusive");
427
+ }
428
+ break;
429
+ case "execution_unit":
430
+ // Ein Scope MIT umschliessender Ausfuehrungseinheit ist bereits in
431
+ // deren `inclusiveValue` enthalten und darf nicht erneut zaehlen.
432
+ if (enclosingExecutionUnit(node, tree.byId) === null) {
433
+ selection.set(node.metricsScopeId, node.executionUnit ? "inclusive" : "self");
434
+ }
435
+ break;
436
+ }
437
+ }
438
+ return selection;
439
+ }
440
+ /**
441
+ * Prueft STRUKTURELL, dass eine Lesart jeden Scope genau einmal zaehlt — die
442
+ * Zusicherung, die `children_exceed_parent` NICHT leisten kann (siehe die
443
+ * Modul-Doku, Abschnitt "Woraus die Doppelzaehlungsfreiheit tatsaechlich
444
+ * folgt", und Punkt 6 von `checkScopeTreeInvariants`).
445
+ *
446
+ * Fuer jeden Scope wird gezaehlt, wie viele Summanden der Lesart seinen
447
+ * Beitrag tragen: er selbst, falls er ausgewaehlt ist, plus jeder echte
448
+ * Vorfahre, der mit `inclusiveValue` ausgewaehlt ist (dessen Summand deckt
449
+ * den ganzen Teilbaum ab). Genau EINER muss es sein.
450
+ *
451
+ * Was die Pruefung NICHT leisten kann: sie sieht die Struktur, nicht die
452
+ * Werte. Ein `inclusiveValue`, der den Beitrag eines Kindes intern doppelt
453
+ * enthaelt, ist aus Zahlen allein nicht erkennbar — dafuer haftet der
454
+ * Aufrufer, der die Werte berechnet hat.
455
+ */
456
+ export function checkScopeCoverage(nodes, reading) {
457
+ return checkSelectionCoverage(nodes, selectionForReading(nodes, reading), reading);
458
+ }
459
+ /**
460
+ * Dieselbe Zaehlpruefung wie `checkScopeCoverage`, aber gegen eine BELIEBIGE
461
+ * Auswahl. Sie ist der eigentliche Kern; `checkScopeCoverage` ist nur die
462
+ * Anwendung auf die Auswahl, die eine der drei Lesarten trifft.
463
+ *
464
+ * Getrennt exportiert, weil die Zusicherung sonst nicht vorfuehrbar waere:
465
+ * die Auswahlen der drei Lesarten koennen `scope_counted_twice` per
466
+ * Konstruktion nicht ausloesen (dort ist ein Scope ausgewaehlt GENAU DANN,
467
+ * wenn er keinen ausgewaehlten `inclusive`-Vorfahren hat). Eine Pruefung,
468
+ * deren Alarmfall ueber die oeffentliche Schnittstelle nicht erreichbar ist,
469
+ * waere eine Behauptung statt einer Pruefung — mit dieser Funktion laesst er
470
+ * sich zeigen, und der Waechter greift, sobald jemand `selectionFor` aendert.
471
+ *
472
+ * @param label Erscheint im Detailtext an der Stelle der Lesart.
473
+ */
474
+ export function checkSelectionCoverage(nodes, selection, label) {
475
+ const tree = resolveTree(nodes);
476
+ const violations = [];
477
+ for (const node of tree.nodes) {
478
+ const carriers = [];
479
+ if (selection.has(node.metricsScopeId))
480
+ carriers.push(node.metricsScopeId);
481
+ const seen = new Set([node.metricsScopeId]);
482
+ let parentId = node.parentScopeId;
483
+ while (parentId !== undefined && !seen.has(parentId)) {
484
+ seen.add(parentId);
485
+ const parent = tree.byId.get(parentId);
486
+ if (parent === undefined)
487
+ break;
488
+ if (selection.get(parentId) === "inclusive")
489
+ carriers.push(parentId);
490
+ parentId = parent.parentScopeId;
491
+ }
492
+ if (carriers.length === 1)
493
+ continue;
494
+ if (carriers.length > 1) {
495
+ violations.push({
496
+ code: "scope_counted_twice",
497
+ metricsScopeId: node.metricsScopeId,
498
+ observed: carriers.length,
499
+ limit: 1,
500
+ detail: `Selection "${label}": the contribution of scope "${node.metricsScopeId}" appears in ` +
501
+ `${String(carriers.length)} contributing terms simultaneously (${carriers.join(", ")}). ` +
502
+ `The total counts the same source text more than once.`,
503
+ });
504
+ continue;
505
+ }
506
+ violations.push({
507
+ code: "scope_uncounted",
508
+ metricsScopeId: node.metricsScopeId,
509
+ observed: 0,
510
+ limit: 1,
511
+ detail: `Selection "${label}": the contribution of scope "${node.metricsScopeId}" belongs to no ` +
512
+ `contributing term. Its content is lost from the total without a replacement; ` +
513
+ `silently losing content is forbidden by E4.`,
514
+ });
515
+ }
516
+ violations.sort((a, b) => compareCodepoints(a.metricsScopeId, b.metricsScopeId) || compareCodepoints(a.code, b.code));
517
+ return violations;
518
+ }
519
+ /**
520
+ * `checkScopeCoverage` fuer ALLE drei Lesarten, Verstoesse deterministisch
521
+ * nach Lesart und Scope sortiert.
522
+ */
523
+ export function checkAllScopeCoverage(nodes) {
524
+ return SCOPE_SUM_READINGS.flatMap((reading) => checkScopeCoverage(nodes, reading));
525
+ }
526
+ /** Naechster Vorfahre, der Ausfuehrungseinheit ist; `null`, wenn es keinen gibt. */
527
+ function enclosingExecutionUnit(node, byId) {
528
+ const seen = new Set([node.metricsScopeId]);
529
+ let parentId = node.parentScopeId;
530
+ while (parentId !== undefined && !seen.has(parentId)) {
531
+ seen.add(parentId);
532
+ const parent = byId.get(parentId);
533
+ if (parent === undefined)
534
+ return null;
535
+ if (parent.executionUnit)
536
+ return parent;
537
+ parentId = parent.parentScopeId;
538
+ }
539
+ return null;
540
+ }
541
+ /**
542
+ * Summiert einen Scope-Baum in allen drei Lesarten, ohne Doppelzaehlung.
543
+ *
544
+ * WIRFT bei jedem Invariantenverstoss (`UntangleError`, Code
545
+ * `ANALYSIS_INCOMPLETE`): eine Summe ueber einen widerspruechlichen Baum ist
546
+ * keine Zahl mit Bedeutung, und ein Hinweis waere hier zu wenig. Wer die
547
+ * Verstoesse anzeigen statt abbrechen will, ruft vorher
548
+ * `checkScopeTreeInvariants` auf.
549
+ */
550
+ export function aggregateScopeTree(nodes, options = {}) {
551
+ assertScopeTreeInvariants(nodes, options);
552
+ const tree = resolveTree(nodes);
553
+ const sumOf = (reading) => selectScopeEntries(nodes, reading).reduce((sum, entry) => sum + entry.value, 0);
554
+ let rootCount = 0;
555
+ let executionUnitRootCount = 0;
556
+ let leafCount = 0;
557
+ let naiveSum = 0;
558
+ let leafOnlySum = 0;
559
+ for (const node of tree.nodes) {
560
+ naiveSum += node.inclusiveValue;
561
+ if (node.parentScopeId === undefined)
562
+ rootCount++;
563
+ if (node.executionUnit && enclosingExecutionUnit(node, tree.byId) === null) {
564
+ executionUnitRootCount++;
565
+ }
566
+ if ((tree.childrenByParent.get(node.metricsScopeId) ?? []).length === 0) {
567
+ leafCount++;
568
+ leafOnlySum += node.inclusiveValue;
569
+ }
570
+ }
571
+ const topLevelSum = sumOf("top_level");
572
+ const selfSum = sumOf("self");
573
+ return {
574
+ scopeCount: tree.nodes.length,
575
+ duplicatesDropped: tree.duplicatesDropped,
576
+ rootCount,
577
+ executionUnitRootCount,
578
+ leafCount,
579
+ topLevelSum,
580
+ executionUnitSum: sumOf("execution_unit"),
581
+ selfSum,
582
+ naiveSum,
583
+ doubleCountedAmount: naiveSum - topLevelSum,
584
+ leafOnlySum,
585
+ leafOnlyDroppedAmount: selfSum - leafOnlySum,
586
+ };
587
+ }
588
+ //# sourceMappingURL=scope-aggregate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-aggregate.js","sourceRoot":"","sources":["../src/scope-aggregate.ts"],"names":[],"mappings":"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"}