@sigloch/graphcode-client 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/panels.d.ts CHANGED
@@ -57,6 +57,32 @@ export interface RecommendationsPanel {
57
57
  total: number;
58
58
  }
59
59
  export declare function recommendationsPanel(violations: RuleViolation[], limit?: number): RecommendationsPanel;
60
+ /** One rule's firings, collapsed: the true count plus a NAMED-capped element sample. */
61
+ export interface ViolationGroup {
62
+ ruleId: string;
63
+ severity: 'error' | 'warning' | 'info';
64
+ /** Firings of this rule over the UNCAPPED input — never derived from `elementIds`. */
65
+ count: number;
66
+ message: string;
67
+ fixHint?: string;
68
+ /** At most `elementLimit` element ids, in input order. */
69
+ elementIds: string[];
70
+ /** How many element ids the cap cut off — the cap is never silent. */
71
+ elementIdsOmitted: number;
72
+ }
73
+ /**
74
+ * Group violations by ruleId — **group first, cap after**.
75
+ *
76
+ * The counting runs over the UNCAPPED violations, never over an already-capped
77
+ * item list: cap-then-count reports "50×" for a rule that fired 60×, and a wrong
78
+ * number is worse than a long list (CR-GVE-250). `elementIds` is cut at
79
+ * `elementLimit` and says via `elementIdsOmitted` how many are missing — a silent
80
+ * cap is exactly the defect this function exists to prevent.
81
+ *
82
+ * Pure projection: the input array is not mutated, and violations without an
83
+ * `elementId` (graph-scoped findings) still count, they just contribute no id.
84
+ */
85
+ export declare function groupViolations(violations: RuleViolation[], elementLimit?: number): ViolationGroup[];
60
86
  export type Freshness = 'live' | 'stale' | 'absent';
61
87
  /**
62
88
  * Two artifact kinds with TWO distinct staleness mechanisms (CR-GC-222):
package/dist/panels.js CHANGED
@@ -27,6 +27,47 @@ export function recommendationsPanel(violations, limit = 5) {
27
27
  });
28
28
  return { items, total: violations.length };
29
29
  }
30
+ /**
31
+ * Group violations by ruleId — **group first, cap after**.
32
+ *
33
+ * The counting runs over the UNCAPPED violations, never over an already-capped
34
+ * item list: cap-then-count reports "50×" for a rule that fired 60×, and a wrong
35
+ * number is worse than a long list (CR-GVE-250). `elementIds` is cut at
36
+ * `elementLimit` and says via `elementIdsOmitted` how many are missing — a silent
37
+ * cap is exactly the defect this function exists to prevent.
38
+ *
39
+ * Pure projection: the input array is not mutated, and violations without an
40
+ * `elementId` (graph-scoped findings) still count, they just contribute no id.
41
+ */
42
+ export function groupViolations(violations, elementLimit = 10) {
43
+ const byRule = new Map();
44
+ for (const v of violations) {
45
+ let g = byRule.get(v.ruleId);
46
+ if (!g) {
47
+ g = {
48
+ ruleId: v.ruleId,
49
+ severity: v.severity,
50
+ count: 0,
51
+ message: v.message,
52
+ fixHint: v.fixHint,
53
+ elementIds: [],
54
+ elementIdsOmitted: 0,
55
+ allElementIds: [],
56
+ };
57
+ byRule.set(v.ruleId, g);
58
+ }
59
+ g.count += 1;
60
+ if (v.elementId)
61
+ g.allElementIds.push(v.elementId);
62
+ }
63
+ return [...byRule.values()]
64
+ .sort((a, b) => b.count - a.count)
65
+ .map(({ allElementIds, ...g }) => ({
66
+ ...g,
67
+ elementIds: allElementIds.slice(0, Math.max(0, elementLimit)),
68
+ elementIdsOmitted: Math.max(0, allElementIds.length - Math.max(0, elementLimit)),
69
+ }));
70
+ }
30
71
  /**
31
72
  * The canonical INCOSE-tab artifact catalog (readiness-artifact-model.md §6). Renders are the
32
73
  * deterministic CR-GC-220 views; the 5 analysis ids are exactly CR-GC-221's creation keys
package/dist/readiness.js CHANGED
@@ -31,6 +31,13 @@ const isCodingProfile = (id) => /^(BQ-|ND-)/.test(id);
31
31
  * resolves — the Presence/Resolution split contracts documents (R-19/R-20/R-26 declare
32
32
  * a binding, RC-01/02/03/04 check it actually resolves on disk). RC-05 (cross-module
33
33
  * import drift) has no presence partner; it is module coupling, so it follows R-23.
34
+ *
35
+ * CR-SM-262: RC-06 folgt RC-05 aus demselben Grund. Ein Praesenz-Partner kaeme nicht in
36
+ * Frage — die Regel prueft ausschliesslich `external === true`, und genau diese Knoten sind
37
+ * von R-20 AUSGENOMMEN ("exempt from the R-20 realRef-binding requirement", ELEMENT_ATTRIBUTES).
38
+ * Sie loest also keine Praesenzforderung auf, sondern stellt eine eigene: das Paket, auf das
39
+ * eine externe Bindung zeigt, muss in den dependencies stehen. Ihr Gegenstand ist damit die
40
+ * Paket-Abhaengigkeit, die groebste Form von Modul-Kopplung — dieselbe Kategorie wie RC-05.
34
41
  */
35
42
  const RC_PRESENCE_PARTNER = {
36
43
  'RC-01': 'R-20', // FUNC realRef → declared symbol
@@ -38,6 +45,7 @@ const RC_PRESENCE_PARTNER = {
38
45
  'RC-03': 'R-26', // SCHEMA realRef → declared export
39
46
  'RC-04': 'R-26', // SCHEMA realRef parsed at its interface
40
47
  'RC-05': 'R-23', // cross-module import the graph does not document
48
+ 'RC-06': 'R-23', // external binding on a package the consumer does not depend on
41
49
  };
42
50
  /**
43
51
  * Phase-Readiness gates (INCOSE technical reviews) → the rules each gate owns.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigloch/graphcode-client",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,11 +37,11 @@
37
37
  "access": "public"
38
38
  },
39
39
  "peerDependencies": {
40
- "@sigloch/contracts": ">=5 <7",
40
+ "@sigloch/contracts": ">=5 <10",
41
41
  "@sigloch/graph-api-core": ">=5 <6"
42
42
  },
43
43
  "devDependencies": {
44
- "@sigloch/contracts": "^6.0.0",
44
+ "@sigloch/contracts": ">=6 <10",
45
45
  "@sigloch/graph-api-core": "^5.0.0"
46
46
  }
47
47
  }