@sigloch/graph-api-core 1.0.0 → 2.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.
package/dist/audit.d.ts CHANGED
@@ -18,6 +18,28 @@ export interface AuditEntry {
18
18
  result: 'applied' | 'rejected' | 'partial';
19
19
  violations?: RuleViolation[];
20
20
  graphVersion: number;
21
+ /**
22
+ * The POSITIVE half of the finding (CR-GC-314): rule IDs that were evaluated for this
23
+ * mutation and returned nothing.
24
+ *
25
+ * `violations` records only what went wrong, so an accepted mutation leaves an empty
26
+ * field — and "rule R-18 checked this edit and passed it" is not recoverable from
27
+ * "no violation". A later learning mechanism can learn from the first statement and
28
+ * nothing at all from the second; that asymmetry is the whole reason this field exists.
29
+ *
30
+ * Rule IDs only, never rule text (REQ-A04). Optional and purely additive: an entry
31
+ * written before this field means "not recorded", NOT "passed nothing" — a consumer
32
+ * must not read absence as an empty pass set (REQ-A05). Old records are deliberately
33
+ * not back-filled: reconstructing them would evaluate against a rule version that did
34
+ * not hold at mutation time, which is itself a provenance violation.
35
+ */
36
+ rulesPassed?: string[];
37
+ /**
38
+ * Version of the rule set this mutation was evaluated against (REQ-A02) — read from
39
+ * the loaded package, never from config, so a rule-set change is visible in the trail
40
+ * at exactly the records it affected.
41
+ */
42
+ rulesetVersion?: string;
21
43
  }
22
44
  export interface AuditLog {
23
45
  record(entry: AuditEntry): Promise<void>;
@@ -12,11 +12,30 @@ export interface RuleViolation {
12
12
  fixHint?: string;
13
13
  /** Carried from the contracts rule: candidate_targets / existing_traces context for fix automation. */
14
14
  context?: unknown;
15
+ /**
16
+ * Stamped by the engine from the rule that produced this violation (CR-GC-312).
17
+ * `false` = visible but not gate-relevant. Absent means gating, so every existing
18
+ * consumer keeps its behaviour without reading the field.
19
+ */
20
+ gating?: boolean;
15
21
  }
16
22
  export interface Rule {
17
23
  id: string;
18
24
  name: string;
19
25
  severity: 'error' | 'warning' | 'info';
26
+ /**
27
+ * May an `error` from this rule BLOCK a write? (CR-GC-312) Default `true`.
28
+ *
29
+ * Severity says how bad a finding is; this says whether the gate acts on it. The
30
+ * two are separate because a rule family can be correct and worth surfacing long
31
+ * before a repo has paid off its backlog — switching one on would otherwise freeze
32
+ * every write on debt the writer did not create. Set `false` to surface a rule in
33
+ * `evaluate`/readiness while it is still being worked down, then promote it.
34
+ *
35
+ * NOT a severity downgrade: the violation keeps `severity: 'error'` and reads as one
36
+ * everywhere it is displayed.
37
+ */
38
+ gating?: boolean;
20
39
  evaluate: (graph: Graph) => RuleViolation[];
21
40
  }
22
41
  export interface RuleEngine {
@@ -10,7 +10,12 @@ export class DefaultRuleEngine {
10
10
  evaluate(graph) {
11
11
  const violations = [];
12
12
  for (const rule of this.rules) {
13
- violations.push(...rule.evaluate(graph));
13
+ // CR-GC-312: stamp `gating` from the rule so a consumer's gate can filter
14
+ // without a second lookup into the catalog. Only stamped when the rule opts
15
+ // OUT — an absent field means gating, the pre-existing behaviour.
16
+ const stamp = rule.gating === false ? { gating: false } : undefined;
17
+ for (const v of rule.evaluate(graph))
18
+ violations.push(stamp ? { ...v, ...stamp } : v);
14
19
  }
15
20
  return violations;
16
21
  }
@@ -9,7 +9,7 @@
9
9
  * - Graph (nodes/edges) ⟷ OntologyGraph (elements/traces)
10
10
  * - RuleViolation (ruleId/…) ⟷ contracts RuleViolation (rule_id/…)
11
11
  */
12
- import { ElementType, TraceType, TRACE_PATTERNS, V3_RULES, MT_RULES, ONTOLOGY_VERSION, } from '@sigloch/contracts/se';
12
+ import { ElementType, TraceType, TRACE_PATTERNS, V3_RULES, MT_RULES, UC_RULES, FC_RULES, SC_RULES, CR_RULES, AO_RULES, FM_RULES, VIEW_RULES, AF_RULES, ONTOLOGY_VERSION, } from '@sigloch/contracts/se';
13
13
  /**
14
14
  * Project an ontology-agnostic Graph (nodes/edges) onto the SE OntologyGraph
15
15
  * (elements/traces) that contracts/se rules evaluate against. Type-specific
@@ -45,16 +45,44 @@ export function projectToOntologyGraph(graph) {
45
45
  /**
46
46
  * The contracts/se rule catalog, adapted to graph-api-core's Rule shape.
47
47
  *
48
- * V3_RULES + MT_RULES (CR-SM-222): the architecture metrics lived in contracts since
49
- * K2 but ran only in aimpro's `evaluateAllRules`, so the governed repos (graphcode,
50
- * graph-view-edit) never saw them. Same adapter, no fork — they inherit by
51
- * consuming this descriptor. MT severities are warning/info, so they stay advisory
52
- * in graphcode's gate.
48
+ * CR-GC-312: this used to be `[...V3_RULES, ...MT_RULES]` — two of the twelve families
49
+ * contracts exports. Everything else (UC, FC, SC, CR, AO, FM, VIEW, AF) was written,
50
+ * versioned and shipped, and then evaluated by nobody: consumers register exactly
51
+ * `SE_DESCRIPTOR.rules`, so ten families were dead weight in the package. Measured on
52
+ * graphcode's SSOT the day this was found: 2 violations reported, 276 findable — among
53
+ * them `CR-R02` ("done but no commitRef", 91×), precisely the graph-vs-reality check
54
+ * the repo believed it had. A use case with no operational chain went unflagged for
55
+ * weeks because `UC-03`/`FC-02` existed and never ran.
56
+ *
57
+ * Two families stay out on purpose:
58
+ * - BQ/ND are the CODING profile (`getRuleDefsForProfile('coding')`), not SE.
59
+ * - RC (conformance) needs `CodeFacts` from a repo checkout, which this package has
60
+ * no access to; graphcode evaluates those itself in `src/conformance.ts`.
61
+ *
62
+ * `gating` (see `Rule`) is what makes the switch-on safe. V3/MT keep their gate power;
63
+ * the newly wired families are advisory until a repo has worked its backlog down —
64
+ * otherwise the 114 pre-existing errors in graphcode's own graph would block every
65
+ * write on debt the writer did not create. Promotion is a per-family decision, not a
66
+ * side effect of being registered.
53
67
  */
54
- const SE_RULES = [...V3_RULES, ...MT_RULES].map((def) => ({
68
+ const GATING_PREFIXES = ['R-', 'RD-', 'MT-'];
69
+ const SE_RULE_DEFS = [
70
+ ...V3_RULES,
71
+ ...MT_RULES,
72
+ ...UC_RULES,
73
+ ...FC_RULES,
74
+ ...SC_RULES,
75
+ ...CR_RULES,
76
+ ...AO_RULES,
77
+ ...FM_RULES,
78
+ ...VIEW_RULES,
79
+ ...AF_RULES,
80
+ ];
81
+ const SE_RULES = SE_RULE_DEFS.map((def) => ({
55
82
  id: def.id,
56
83
  name: def.name,
57
84
  severity: def.severity,
85
+ gating: GATING_PREFIXES.some((p) => def.id.startsWith(p)),
58
86
  evaluate: (graph) => def.evaluate(projectToOntologyGraph(graph)).map((v) => ({
59
87
  ruleId: v.rule_id,
60
88
  ruleName: def.name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigloch/graph-api-core",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  "prepublishOnly": "npm run build && npm run test"
22
22
  },
23
23
  "dependencies": {
24
- "@sigloch/contracts": "^1.0.0",
24
+ "@sigloch/contracts": "^3.2.0",
25
25
  "zod": "^4.3.6"
26
26
  },
27
27
  "license": "MIT",